300 const Eigen::MatrixXd& density_matrix)
const {
301 assert(density_matrix.isApprox(density_matrix.transpose()) &&
302 "Density matrix has to be symmetric!");
306#pragma omp parallel for schedule(guided) reduction(+ : vxc)
307 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
317 1.e-40 / double(density_matrix.rows()) / double(density_matrix.rows());
318 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
324 Eigen::MatrixXd Vxc_here = Eigen::MatrixXd::Zero(nf, nf);
325 Eigen::MatrixXd phi(nf, block);
326 Eigen::MatrixXd dphi(nf, 3 * block);
327 Eigen::MatrixXd y(nf, block);
328 Eigen::MatrixXd a(nf, block);
329 std::vector<Index> kept;
330 std::vector<double> rho, sigma, exc, vrho, vsigma;
331 std::vector<Eigen::Vector3d> grad;
332 double EXC_box = 0.0;
334 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
337 for (
Index start = 0; start < box.
size(); start += block) {
338 const Index nb = std::min(block, box.
size() - start);
339 for (
Index p = 0; p < nb; ++p) {
342 y.leftCols(nb).noalias() = DMAT_here * phi.leftCols(nb);
348 for (
Index p = 0; p < nb; ++p) {
349 const double r = 0.5 * phi.col(p).dot(y.col(p));
350 if (r * weights[start + p] < 1.e-20) {
353 const Eigen::Vector3d g =
354 dphi.middleCols(3 * p, 3).transpose() * y.col(p);
357 sigma.push_back(g.squaredNorm());
372 for (
Index k = 0; k < nk; ++k) {
373 const Index p = kept[k];
374 const double w = weights[start + p];
375 EXC_box += w * rho[k] * exc[k];
376 a.col(k) = (w * 0.5 * vrho[k]) * phi.col(p);
378 a.col(k).noalias() +=
379 (w * 2.0 * vsigma[k]) * (dphi.middleCols(3 * p, 3) * grad[k]);
382 phi.col(k) = phi.col(p);
385 Vxc_here.noalias() += a.leftCols(nk) * phi.leftCols(nk).transpose();
483 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
484 const std::vector<std::array<Eigen::MatrixXd, 2>>& response)
const {
485 const Index n_ao = dmat_alpha.rows();
487 std::vector<std::array<Eigen::MatrixXd, 2>> result(
488 static_cast<std::size_t
>(n_resp),
489 {Eigen::MatrixXd::Zero(n_ao, n_ao), Eigen::MatrixXd::Zero(n_ao, n_ao)});
493 auto wrong_size = [n_ao](
const std::array<Eigen::MatrixXd, 2>& r) {
494 return r[0].rows() != n_ao || r[0].cols() != n_ao || r[1].rows() != n_ao ||
497 if (std::any_of(response.begin(), response.end(), wrong_size)) {
498 throw std::runtime_error(
499 "IntegrateFXCSpin: response matrix does not match the density "
504 const double rho[2] = {0.1, 0.05};
505 const double sigma[3] = {0.01, 0.005, 0.004};
506 double vs[3], rr[3], rs[6], ss[6];
510#pragma omp parallel for schedule(guided)
511 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
518 std::vector<Eigen::MatrixXd> dDa(
static_cast<std::size_t
>(n_resp));
519 std::vector<Eigen::MatrixXd> dDb(
static_cast<std::size_t
>(n_resp));
520 for (
Index k = 0; k < n_resp; ++k) {
526 std::vector<Eigen::MatrixXd> fxc_a(
static_cast<std::size_t
>(n_resp),
527 Eigen::MatrixXd::Zero(nf, nf));
528 std::vector<Eigen::MatrixXd> fxc_b(
static_cast<std::size_t
>(n_resp),
529 Eigen::MatrixXd::Zero(nf, nf));
530 Eigen::MatrixXd phi(nf, block);
531 Eigen::MatrixXd dphi(nf, 3 * block);
532 Eigen::MatrixXd ya(nf, block);
533 Eigen::MatrixXd yb(nf, block);
534 Eigen::MatrixXd yka(nf, block);
535 Eigen::MatrixXd ykb(nf, block);
536 Eigen::MatrixXd aa(nf, block);
537 Eigen::MatrixXd ab(nf, block);
538 std::vector<Index> kept;
539 std::vector<double> rho, sigma, vsigma, v2rho2, v2rhosigma, v2sigma2;
540 std::vector<Eigen::Vector3d> grad_a, grad_b;
541 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
544 for (
Index start = 0; start < box.
size(); start += block) {
545 const Index nb = std::min(block, box.
size() - start);
546 for (
Index p = 0; p < nb; ++p) {
549 ya.leftCols(nb).noalias() = DMa * phi.leftCols(nb);
550 yb.leftCols(nb).noalias() = DMb * phi.leftCols(nb);
556 for (
Index p = 0; p < nb; ++p) {
557 const double rho_a = phi.col(p).dot(ya.col(p));
558 const double rho_b = phi.col(p).dot(yb.col(p));
559 if ((rho_a + rho_b) * weights[start + p] < 1.e-20) {
562 const Eigen::Vector3d ga =
563 2.0 * (dphi.middleCols(3 * p, 3).transpose() * ya.col(p));
564 const Eigen::Vector3d gb =
565 2.0 * (dphi.middleCols(3 * p, 3).transpose() * yb.col(p));
567 rho.push_back(rho_a);
568 rho.push_back(rho_b);
569 sigma.push_back(ga.dot(ga));
570 sigma.push_back(ga.dot(gb));
571 sigma.push_back(gb.dot(gb));
572 grad_a.push_back(ga);
573 grad_b.push_back(gb);
579 vsigma.resize(3 * nk);
580 v2rho2.resize(3 * nk);
581 v2rhosigma.resize(6 * nk);
582 v2sigma2.resize(6 * nk);
584 v2rho2.data(), v2rhosigma.data(), v2sigma2.data());
585 Eigen::MatrixXd phik(nf, nk);
586 for (
Index q = 0; q < nk; ++q) {
587 phik.col(q) = phi.col(kept[q]);
590 for (
Index k = 0; k < n_resp; ++k) {
591 yka.leftCols(nb).noalias() = dDa[std::size_t(k)] * phi.leftCols(nb);
592 ykb.leftCols(nb).noalias() = dDb[std::size_t(k)] * phi.leftCols(nb);
593 for (
Index q = 0; q < nk; ++q) {
594 const Index p = kept[q];
595 const double w = weights[start + p];
596 const double dra = phi.col(p).dot(yka.col(p));
597 const double drb = phi.col(p).dot(ykb.col(p));
598 const double* r2 = &v2rho2[3 * q];
600 const double dva = r2[0] * dra + r2[1] * drb;
601 const double dvb = r2[1] * dra + r2[2] * drb;
602 aa.col(q) = (w * 0.5 * dva) * phi.col(p);
603 ab.col(q) = (w * 0.5 * dvb) * phi.col(p);
606 const auto d = dphi.middleCols(3 * p, 3);
607 const Eigen::Vector3d dga = 2.0 * (d.transpose() * yka.col(p));
608 const Eigen::Vector3d dgb = 2.0 * (d.transpose() * ykb.col(p));
609 const Eigen::Vector3d& ga = grad_a[q];
610 const Eigen::Vector3d& gb = grad_b[q];
611 const double ds[3] = {2.0 * ga.dot(dga), ga.dot(dgb) + dga.dot(gb),
613 const double* rs = &v2rhosigma[6 * q];
614 const double* s2 = &v2sigma2[6 * q];
615 const double* vs = &vsigma[3 * q];
617 const double S[3][3] = {{s2[0], s2[1], s2[2]},
618 {s2[1], s2[3], s2[4]},
619 {s2[2], s2[4], s2[5]}};
620 const double dva = r2[0] * dra + r2[1] * drb + rs[0] * ds[0] +
621 rs[1] * ds[1] + rs[2] * ds[2];
622 const double dvb = r2[1] * dra + r2[2] * drb + rs[3] * ds[0] +
623 rs[4] * ds[1] + rs[5] * ds[2];
625 for (
int c = 0; c < 3; ++c) {
626 dvs[c] = rs[c] * dra + rs[3 + c] * drb +
S[c][0] * ds[0] +
627 S[c][1] * ds[1] +
S[c][2] * ds[2];
629 const Eigen::Vector3d vec_a =
630 2.0 * dvs[0] * ga + 2.0 * vs[0] * dga + dvs[1] * gb + vs[1] * dgb;
631 const Eigen::Vector3d vec_b =
632 2.0 * dvs[2] * gb + 2.0 * vs[2] * dgb + dvs[1] * ga + vs[1] * dga;
633 aa.col(q) = (w * 0.5 * dva) * phi.col(p) + w * (d * vec_a);
634 ab.col(q) = (w * 0.5 * dvb) * phi.col(p) + w * (d * vec_b);
636 fxc_a[std::size_t(k)].noalias() += aa.leftCols(nk) * phik.transpose();
637 fxc_b[std::size_t(k)].noalias() += ab.leftCols(nk) * phik.transpose();
642 for (
Index k = 0; k < n_resp; ++k) {
643 box.
AddtoBigMatrix(result[std::size_t(k)][0], fxc_a[std::size_t(k)]);
644 box.
AddtoBigMatrix(result[std::size_t(k)][1], fxc_b[std::size_t(k)]);
648 for (std::array<Eigen::MatrixXd, 2>& m : result) {
649 m[0] = (m[0] + m[0].transpose()).eval();
650 m[1] = (m[1] + m[1].transpose()).eval();
664 const Eigen::MatrixXd& density_matrix,
665 const std::vector<Eigen::MatrixXd>& response_matrices)
const {
666 const Index n_ao = density_matrix.rows();
667 const Index n_resp =
Index(response_matrices.size());
668 std::vector<Eigen::MatrixXd> result(
static_cast<std::size_t
>(n_resp),
669 Eigen::MatrixXd::Zero(n_ao, n_ao));
673 if (std::any_of(response_matrices.begin(), response_matrices.end(),
674 [n_ao](
const Eigen::MatrixXd& m) {
675 return m.rows() != n_ao || m.cols() != n_ao;
677 throw std::runtime_error(
678 "IntegrateFXC: response matrix does not match the density matrix");
682 const double rho = 0.1;
683 const double sigma = 0.01;
684 double vs, rr, rs, ss;
688#pragma omp parallel for schedule(guided)
689 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
695 std::vector<Eigen::MatrixXd> dmat_k(
static_cast<std::size_t
>(n_resp));
696 for (
Index k = 0; k < n_resp; ++k) {
697 dmat_k[std::size_t(k)] =
702 std::vector<Eigen::MatrixXd> fxc_here(
static_cast<std::size_t
>(n_resp),
703 Eigen::MatrixXd::Zero(nf, nf));
704 Eigen::MatrixXd phi(nf, block);
705 Eigen::MatrixXd dphi(nf, 3 * block);
706 Eigen::MatrixXd y(nf, block);
707 Eigen::MatrixXd yk(nf, block);
708 Eigen::MatrixXd a(nf, block);
709 std::vector<Index> kept;
710 std::vector<double> rho, sigma, vsigma, v2rho2, v2rhosigma, v2sigma2;
711 std::vector<Eigen::Vector3d> grad;
712 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
715 for (
Index start = 0; start < box.
size(); start += block) {
716 const Index nb = std::min(block, box.
size() - start);
717 for (
Index p = 0; p < nb; ++p) {
720 y.leftCols(nb).noalias() = DMAT_here * phi.leftCols(nb);
725 for (
Index p = 0; p < nb; ++p) {
726 const double r = 0.5 * phi.col(p).dot(y.col(p));
727 if (r * weights[start + p] < 1.e-20) {
730 const Eigen::Vector3d g =
731 dphi.middleCols(3 * p, 3).transpose() * y.col(p);
734 sigma.push_back(g.squaredNorm());
743 v2rhosigma.resize(nk);
746 v2rho2.data(), v2rhosigma.data(), v2sigma2.data());
747 Eigen::MatrixXd phik(nf, nk);
748 for (
Index q = 0; q < nk; ++q) {
749 phik.col(q) = phi.col(kept[q]);
752 for (
Index k = 0; k < n_resp; ++k) {
753 yk.leftCols(nb).noalias() = dmat_k[std::size_t(k)] * phi.leftCols(nb);
754 for (
Index q = 0; q < nk; ++q) {
755 const Index p = kept[q];
756 const double w = weights[start + p];
757 const double drho = 0.5 * phi.col(p).dot(yk.col(p));
759 const Eigen::Vector3d dg =
760 dphi.middleCols(3 * p, 3).transpose() * yk.col(p);
761 const double dsigma = 2.0 * grad[q].dot(dg);
762 const double dv_rho = v2rho2[q] * drho + v2rhosigma[q] * dsigma;
763 const double dv_sigma = v2rhosigma[q] * drho + v2sigma2[q] * dsigma;
764 const Eigen::Vector3d vec =
765 2.0 * (dv_sigma * grad[q] + vsigma[q] * dg);
766 a.col(q) = (w * 0.5 * dv_rho) * phi.col(p) +
767 w * (dphi.middleCols(3 * p, 3) * vec);
769 a.col(q) = (w * 0.5 * v2rho2[q] * drho) * phi.col(p);
772 fxc_here[std::size_t(k)].noalias() += a.leftCols(nk) * phik.transpose();
777 for (
Index k = 0; k < n_resp; ++k) {
778 box.
AddtoBigMatrix(result[std::size_t(k)], fxc_here[std::size_t(k)]);
782 for (Eigen::MatrixXd& m : result) {
783 m = (m + m.transpose()).eval();
807 const Eigen::MatrixXd& density_matrix,
const AOBasis& dftbasis)
const {
808 assert(density_matrix.isApprox(density_matrix.transpose()) &&
809 "Density matrix has to be symmetric!");
813 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
814 Eigen::MatrixXd::Zero(natoms, 3));
816 std::exception_ptr eptr_pulay =
nullptr;
817#pragma omp parallel for schedule(guided)
818 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
826 const Eigen::MatrixXd DMAT_here =
829 double cutoff = 1.e-40 / double(density_matrix.rows()) /
830 double(density_matrix.rows());
831 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
836 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
837 const std::vector<const AOShell*>& shells = box.
getShells();
838 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
839 for (
size_t s = 0; s < shells.size(); ++s) {
840 Index atom = shells[s]->getAtomIndex();
841 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
842 local_idx_to_atom[ao_ranges[s].start + k] = atom;
846 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
854 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
855 double rho = 0.5 * temp.dot(ao.
values);
856 const double weight = weights[p];
858 if (rho * weight < 1.e-20) {
862 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
885 Eigen::MatrixX3d Gmat = DMAT_here * ao.
derivatives;
886 Eigen::VectorXd s_vec = Gmat * rho_grad;
888 Eigen::Matrix3d Hessian_rho = Eigen::Matrix3d::Zero();
890 Hessian_rho += temp(mu) * ao.
hessians[mu];
892 Eigen::Matrix3d M = ao.
derivatives.transpose() * Gmat;
893 Hessian_rho += 0.5 * (M + M.transpose());
895 Index owner_of_point_sigma = owner_atoms[p];
896 Eigen::Vector3d dsigma_translation = 2.0 * (Hessian_rho * rho_grad);
897 grad_thread[thread_id].row(owner_of_point_sigma) +=
898 (weight * xc.
df_dsigma * dsigma_translation).transpose();
908 Index owner_of_point = owner_atoms[p];
909 grad_thread[thread_id].row(owner_of_point) +=
910 (weight * xc.
df_drho * rho_grad).transpose();
916 Index atom = local_idx_to_atom[mu];
917 Eigen::Vector3d contribution = -weight * xc.
df_drho * temp(mu) *
920 Eigen::Vector3d dsigma_basis_mu =
921 -2.0 * (ao.
derivatives.row(mu).transpose() * s_vec(mu) +
922 temp(mu) * (ao.
hessians[mu] * rho_grad));
923 contribution += weight * xc.
df_dsigma * dsigma_basis_mu;
924 grad_thread[thread_id].row(atom) += contribution.transpose();
931 eptr_pulay = std::current_exception();
937 std::rethrow_exception(eptr_pulay);
940 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
941 for (
Index t = 0; t < nthreads; ++t) {
942 grad += grad_thread[t];
951 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta)
const {
952 assert(dmat_alpha.isApprox(dmat_alpha.transpose()) &&
953 "Alpha density matrix has to be symmetric!");
954 assert(dmat_beta.isApprox(dmat_beta.transpose()) &&
955 "Beta density matrix has to be symmetric!");
959 Eigen::MatrixXd::Zero(dmat_alpha.rows(), dmat_alpha.cols());
960 result.
vxc_beta = Eigen::MatrixXd::Zero(dmat_beta.rows(), dmat_beta.cols());
964 Eigen::MatrixXd vxc_alpha_private =
965 Eigen::MatrixXd::Zero(dmat_alpha.rows(), dmat_alpha.cols());
966 Eigen::MatrixXd vxc_beta_private =
967 Eigen::MatrixXd::Zero(dmat_beta.rows(), dmat_beta.cols());
968 double exc_private = 0.0;
970 std::vector<Index> kept;
971 std::vector<double> rho, sigma, exc, vrho, vsigma;
972 std::vector<Eigen::Vector3d> grad_a, grad_b;
974#pragma omp for schedule(guided)
975 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
985 1.e-40 / double(dmat_alpha.rows()) / double(dmat_alpha.rows());
986 if (std::max(DMa.cwiseAbs2().maxCoeff(), DMb.cwiseAbs2().maxCoeff()) <
993 Eigen::MatrixXd Vxc_a_here = Eigen::MatrixXd::Zero(nf, nf);
994 Eigen::MatrixXd Vxc_b_here = Eigen::MatrixXd::Zero(nf, nf);
995 Eigen::MatrixXd phi(nf, block);
996 Eigen::MatrixXd dphi(nf, 3 * block);
997 Eigen::MatrixXd ya(nf, block);
998 Eigen::MatrixXd yb(nf, block);
999 Eigen::MatrixXd aa(nf, block);
1000 Eigen::MatrixXd ab(nf, block);
1002 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1005 for (
Index start = 0; start < box.
size(); start += block) {
1006 const Index nb = std::min(block, box.
size() - start);
1007 for (
Index p = 0; p < nb; ++p) {
1010 ya.leftCols(nb).noalias() = DMa * phi.leftCols(nb);
1011 yb.leftCols(nb).noalias() = DMb * phi.leftCols(nb);
1018 for (
Index p = 0; p < nb; ++p) {
1019 const double rho_a = phi.col(p).dot(ya.col(p));
1020 const double rho_b = phi.col(p).dot(yb.col(p));
1021 if ((rho_a + rho_b) * weights[start + p] < 1.e-20) {
1024 const Eigen::Vector3d ga =
1025 2.0 * (dphi.middleCols(3 * p, 3).transpose() * ya.col(p));
1026 const Eigen::Vector3d gb =
1027 2.0 * (dphi.middleCols(3 * p, 3).transpose() * yb.col(p));
1029 rho.push_back(rho_a);
1030 rho.push_back(rho_b);
1031 sigma.push_back(ga.dot(ga));
1032 sigma.push_back(ga.dot(gb));
1033 sigma.push_back(gb.dot(gb));
1034 grad_a.push_back(ga);
1035 grad_b.push_back(gb);
1042 vrho.resize(2 * nk);
1043 vsigma.resize(3 * nk);
1045 vrho.data(), vsigma.data());
1047 for (
Index k = 0; k < nk; ++k) {
1048 const Index p = kept[k];
1049 const double w = weights[start + p];
1050 exc_private += w * (rho[2 * k] + rho[2 * k + 1]) * exc[k];
1052 aa.col(k) = (w * 0.5 * vrho[2 * k]) * phi.col(p);
1053 ab.col(k) = (w * 0.5 * vrho[2 * k + 1]) * phi.col(p);
1055 const auto d = dphi.middleCols(3 * p, 3);
1056 const Eigen::VectorXd g_a = d * grad_a[k];
1057 const Eigen::VectorXd g_b = d * grad_b[k];
1058 const double vs_aa = vsigma[3 * k];
1059 const double vs_ab = vsigma[3 * k + 1];
1060 const double vs_bb = vsigma[3 * k + 2];
1061 aa.col(k).noalias() += w * (2.0 * vs_aa * g_a + vs_ab * g_b);
1062 ab.col(k).noalias() += w * (vs_ab * g_a + 2.0 * vs_bb * g_b);
1065 phi.col(k) = phi.col(p);
1068 Vxc_a_here.noalias() += aa.leftCols(nk) * phi.leftCols(nk).transpose();
1069 Vxc_b_here.noalias() += ab.leftCols(nk) * phi.leftCols(nk).transpose();
1078 result.
vxc_alpha += vxc_alpha_private + vxc_alpha_private.transpose();
1079 result.
vxc_beta += vxc_beta_private + vxc_beta_private.transpose();
1080 result.
energy += exc_private;
1118 const Eigen::MatrixXd& density_matrix,
const QMMolecule& atoms)
const {
1120 Eigen::MatrixXd Rij =
grid_.CalcInverseAtomDist(atoms);
1123 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1124 Eigen::MatrixXd::Zero(natoms, 3));
1126 std::exception_ptr eptr_weight =
nullptr;
1127#pragma omp parallel for schedule(guided)
1128 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1136 const Eigen::MatrixXd DMAT_here =
1138 double cutoff = 1.e-40 / double(density_matrix.rows()) /
1139 double(density_matrix.rows());
1140 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
1144 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1146 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1148 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
1150 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
1151 double rho = 0.5 * temp.dot(ao.
values);
1152 double weight = weights[pidx];
1153 if (rho * weight < 1.e-20) {
1156 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
1160 Index owner = owner_atoms[pidx];
1164 throw std::runtime_error(
1165 "GridWeightGradient: grid point has no owner atom set; the "
1166 "grid must be built with Vxc_Grid::GridSetup.");
1172 const Eigen::Vector3d& point = points[pidx];
1173 Eigen::VectorXd rq(natoms);
1174 for (
Index k = 0; k < natoms; ++k) {
1175 rq(k) = (point - atoms[k].
getPos()).norm();
1182 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
1183 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
1184 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
1188 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
1189 for (
Index ii = 1; ii < natoms; ++ii) {
1190 for (
Index jj = 0; jj < ii; ++jj) {
1191 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
1192 mu_table(jj, ii) = mu;
1193 if (mu > kSSWCutoff) {
1196 }
else if (mu < -kSSWCutoff) {
1200 double sk = SSWValue(mu);
1201 sk_table(jj, ii) = sk;
1203 p(ii) *= (1.0 - sk);
1207 double wsum = p.sum();
1208 double w_owner = p(owner) / wsum;
1213 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1214 if (A == owner && A == k) {
1215 return Eigen::Vector3d::Zero();
1216 }
else if (A == owner) {
1217 return (point - atoms[k].getPos()) / rq(k);
1218 }
else if (A == k) {
1219 return -(point - atoms[k].
getPos()) / rq(k);
1221 return Eigen::Vector3d::Zero();
1224 Eigen::Vector3d rvec = atoms[a].
getPos() - atoms[b].
getPos();
1225 double Rab = rvec.norm();
1228 }
else if (A == b) {
1231 return Eigen::Vector3d::Zero();
1235 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
1236 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
1237 double Rab = 1.0 / Rij(a, b);
1238 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
1239 double mu = mu_table(a, b);
1240 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
1242 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1247 constexpr double kNegligibleP = 1.e-8;
1248 if (p(k) < kNegligibleP) {
1249 return Eigen::Vector3d::Zero();
1251 Eigen::Vector3d total = Eigen::Vector3d::Zero();
1252 for (
Index b = k + 1; b < natoms; ++b) {
1253 if (hard(k, b) != 0) {
1256 double skv = sk_table(k, b);
1257 if (skv < kNegligibleP) {
1260 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
1262 for (
Index a = 0; a < k; ++a) {
1263 if (hard(a, k) != 0) {
1266 double skv = sk_table(a, k);
1267 double one_minus_skv = 1.0 - skv;
1268 if (one_minus_skv < kNegligibleP) {
1271 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
1274 return p(k) * total;
1279 constexpr double kNegligibleWOwner = 1.e-8;
1280 if (w_owner < kNegligibleWOwner) {
1289 double C_p = weight / w_owner;
1291 double prefactor = C_p * rho * xc.
f_xc;
1293 for (
Index A = 0; A < natoms; ++A) {
1294 Eigen::Vector3d dp_owner = dp_dR(owner, A);
1295 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
1296 for (
Index k = 0; k < natoms; ++k) {
1297 dwsum += dp_dR(k, A);
1299 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
1300 Eigen::Vector3d contribution = prefactor * dw;
1301 grad_thread[thread_id].row(A) += contribution.transpose();
1308 eptr_weight = std::current_exception();
1314 std::rethrow_exception(eptr_weight);
1317 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1318 for (
Index t = 0; t < nthreads; ++t) {
1319 grad += grad_thread[t];
1326 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
1327 const AOBasis& dftbasis)
const {
1336 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1337 Eigen::MatrixXd::Zero(natoms, 3));
1339 std::exception_ptr eptr_pulay_uks =
nullptr;
1340#pragma omp parallel for schedule(guided)
1341 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1357 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
1358 const std::vector<const AOShell*>& shells = box.
getShells();
1359 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
1360 for (
size_t s = 0; s < shells.size(); ++s) {
1361 Index atom = shells[s]->getAtomIndex();
1362 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
1363 local_idx_to_atom[ao_ranges[s].start + k] = atom;
1366 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1368 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1371 for (
Index p = 0; p < box.
size(); ++p) {
1374 Eigen::VectorXd temp_a = DMa * ao.
values;
1375 Eigen::VectorXd temp_b = DMb * ao.
values;
1376 const double rho_a = ao.
values.dot(temp_a);
1377 const double rho_b = ao.
values.dot(temp_b);
1378 const double rho = rho_a + rho_b;
1379 const double weight = weights[p];
1381 if (rho * weight < 1.e-20) {
1385 const Eigen::Vector3d rho_a_grad =
1387 const Eigen::Vector3d rho_b_grad =
1389 const double sigma_aa = rho_a_grad.dot(rho_a_grad);
1390 const double sigma_ab = rho_a_grad.dot(rho_b_grad);
1391 const double sigma_bb = rho_b_grad.dot(rho_b_grad);
1397 Index owner_of_point = owner_atoms[p];
1398 grad_thread[thread_id].row(owner_of_point) +=
1399 (weight * (xc.
vrho_a * rho_a_grad + xc.
vrho_b * rho_b_grad))
1405 Eigen::MatrixX3d Gmat_a = 2.0 * (DMa * ao.
derivatives);
1406 Eigen::MatrixX3d Gmat_b = 2.0 * (DMb * ao.
derivatives);
1407 Eigen::Vector3d V_a =
1409 Eigen::Vector3d V_b =
1414 Eigen::Matrix3d Hessian_rho_a = Eigen::Matrix3d::Zero();
1415 Eigen::Matrix3d Hessian_rho_b = Eigen::Matrix3d::Zero();
1417 Hessian_rho_a += 2.0 * temp_a(mu) * ao.
hessians[mu];
1418 Hessian_rho_b += 2.0 * temp_b(mu) * ao.
hessians[mu];
1420 Eigen::Matrix3d Ma = ao.
derivatives.transpose() * Gmat_a;
1421 Eigen::Matrix3d Mb = ao.
derivatives.transpose() * Gmat_b;
1422 Hessian_rho_a += 0.5 * (Ma + Ma.transpose());
1423 Hessian_rho_b += 0.5 * (Mb + Mb.transpose());
1425 grad_thread[thread_id].row(owner_of_point) +=
1426 (weight * (Hessian_rho_a * V_a + Hessian_rho_b * V_b)).transpose();
1430 Eigen::VectorXd Gmat_a_dot_Va = Gmat_a * V_a;
1431 Eigen::VectorXd Gmat_b_dot_Vb = Gmat_b * V_b;
1433 Index atom = local_idx_to_atom[mu];
1434 Eigen::Vector3d lda_contribution =
1438 Eigen::Vector3d sigma_contribution =
1440 (ao.
derivatives.row(mu).transpose() * Gmat_a_dot_Va(mu) +
1441 2.0 * temp_a(mu) * (ao.
hessians[mu] * V_a) +
1442 ao.
derivatives.row(mu).transpose() * Gmat_b_dot_Vb(mu) +
1443 2.0 * temp_b(mu) * (ao.
hessians[mu] * V_b));
1444 grad_thread[thread_id].row(atom) +=
1445 (lda_contribution + sigma_contribution).transpose();
1451 if (!eptr_pulay_uks) {
1452 eptr_pulay_uks = std::current_exception();
1457 if (eptr_pulay_uks) {
1458 std::rethrow_exception(eptr_pulay_uks);
1461 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1462 for (
Index t = 0; t < nthreads; ++t) {
1463 grad += grad_thread[t];
1470 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
1478 Eigen::MatrixXd Rij =
grid_.CalcInverseAtomDist(atoms);
1481 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1482 Eigen::MatrixXd::Zero(natoms, 3));
1484 std::exception_ptr eptr_weight_uks =
nullptr;
1485#pragma omp parallel for schedule(guided)
1486 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1497 1.e-40 / double(dmat_alpha.rows()) / double(dmat_alpha.rows());
1498 if (std::max(DMa.cwiseAbs2().maxCoeff(), DMb.cwiseAbs2().maxCoeff()) <
1503 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1505 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1507 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
1509 Eigen::VectorXd temp_a = DMa * ao.
values;
1510 Eigen::VectorXd temp_b = DMb * ao.
values;
1511 const double rho_a = ao.
values.dot(temp_a);
1512 const double rho_b = ao.
values.dot(temp_b);
1513 const double rho = rho_a + rho_b;
1514 double weight = weights[pidx];
1515 if (rho * weight < 1.e-20) {
1518 const Eigen::Vector3d rho_a_grad =
1520 const Eigen::Vector3d rho_b_grad =
1522 const double sigma_aa = rho_a_grad.dot(rho_a_grad);
1523 const double sigma_ab = rho_a_grad.dot(rho_b_grad);
1524 const double sigma_bb = rho_b_grad.dot(rho_b_grad);
1528 Index owner = owner_atoms[pidx];
1530 throw std::runtime_error(
1531 "GridWeightGradientUKS: grid point has no owner atom set; the "
1532 "grid must be built with Vxc_Grid::GridSetup.");
1535 const Eigen::Vector3d& point = points[pidx];
1536 Eigen::VectorXd rq(natoms);
1537 for (
Index k = 0; k < natoms; ++k) {
1538 rq(k) = (point - atoms[k].
getPos()).norm();
1541 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
1542 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
1543 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
1544 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
1545 for (
Index ii = 1; ii < natoms; ++ii) {
1546 for (
Index jj = 0; jj < ii; ++jj) {
1547 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
1548 mu_table(jj, ii) = mu;
1549 if (mu > kSSWCutoff) {
1552 }
else if (mu < -kSSWCutoff) {
1556 double sk = SSWValue(mu);
1557 sk_table(jj, ii) = sk;
1559 p(ii) *= (1.0 - sk);
1563 double wsum = p.sum();
1564 double w_owner = p(owner) / wsum;
1566 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1567 if (A == owner && A == k) {
1568 return Eigen::Vector3d::Zero();
1569 }
else if (A == owner) {
1570 return (point - atoms[k].getPos()) / rq(k);
1571 }
else if (A == k) {
1572 return -(point - atoms[k].
getPos()) / rq(k);
1574 return Eigen::Vector3d::Zero();
1577 Eigen::Vector3d rvec = atoms[a].
getPos() - atoms[b].
getPos();
1578 double Rab = rvec.norm();
1581 }
else if (A == b) {
1584 return Eigen::Vector3d::Zero();
1587 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
1588 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
1589 double Rab = 1.0 / Rij(a, b);
1590 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
1591 double mu = mu_table(a, b);
1592 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
1594 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1595 constexpr double kNegligibleP = 1.e-8;
1596 if (p(k) < kNegligibleP) {
1597 return Eigen::Vector3d::Zero();
1599 Eigen::Vector3d total = Eigen::Vector3d::Zero();
1600 for (
Index b = k + 1; b < natoms; ++b) {
1601 if (hard(k, b) != 0) {
1604 double skv = sk_table(k, b);
1605 if (skv < kNegligibleP) {
1608 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
1610 for (
Index a = 0; a < k; ++a) {
1611 if (hard(a, k) != 0) {
1614 double skv = sk_table(a, k);
1615 double one_minus_skv = 1.0 - skv;
1616 if (one_minus_skv < kNegligibleP) {
1619 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
1622 return p(k) * total;
1625 constexpr double kNegligibleWOwner = 1.e-8;
1626 if (w_owner < kNegligibleWOwner) {
1629 double C_p = weight / w_owner;
1630 double prefactor = C_p * rho * xc.
f_xc;
1632 for (
Index A = 0; A < natoms; ++A) {
1633 Eigen::Vector3d dp_owner = dp_dR(owner, A);
1634 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
1635 for (
Index k = 0; k < natoms; ++k) {
1636 dwsum += dp_dR(k, A);
1638 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
1639 Eigen::Vector3d contribution = prefactor * dw;
1640 grad_thread[thread_id].row(A) += contribution.transpose();
1646 if (!eptr_weight_uks) {
1647 eptr_weight_uks = std::current_exception();
1652 if (eptr_weight_uks) {
1653 std::rethrow_exception(eptr_weight_uks);
1656 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1657 for (
Index t = 0; t < nthreads; ++t) {
1658 grad += grad_thread[t];