57 double exactexchange = 0.0;
60 std::vector<std::string> functional_names =
63 if (functional_names.size() > 2) {
64 throw std::runtime_error(
"Too many functional names");
65 }
else if (functional_names.empty()) {
66 throw std::runtime_error(
"Specify at least one functional");
69 for (
const std::string& functional_name : functional_names) {
70 int func_id = map.getID(functional_name);
77 if (xc_func_init(&func, func_id, XC_UNPOLARIZED) != 0) {
78 throw std::runtime_error(
79 (boost::format(
"Functional %s not found\n") % functional_name).str());
82 if (exactexchange > 0 && func.cam_alpha > 0) {
84 throw std::runtime_error(
85 "You have specified two functionals with exact exchange");
88 exactexchange += func.cam_alpha;
262 const Eigen::MatrixXd& density_matrix)
const {
263 assert(density_matrix.isApprox(density_matrix.transpose()) &&
264 "Density matrix has to be symmetric!");
268#pragma omp parallel for schedule(guided) reduction(+ : vxc)
269 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
279 1.e-40 / double(density_matrix.rows()) / double(density_matrix.rows());
280 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
286 Eigen::MatrixXd Vxc_here = Eigen::MatrixXd::Zero(nf, nf);
287 Eigen::MatrixXd phi(nf, block);
288 Eigen::MatrixXd dphi(nf, 3 * block);
289 Eigen::MatrixXd y(nf, block);
290 Eigen::MatrixXd a(nf, block);
291 std::vector<Index> kept;
292 std::vector<double> rho, sigma, exc, vrho, vsigma;
293 std::vector<Eigen::Vector3d> grad;
294 double EXC_box = 0.0;
296 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
299 for (
Index start = 0; start < box.
size(); start += block) {
300 const Index nb = std::min(block, box.
size() - start);
301 for (
Index p = 0; p < nb; ++p) {
304 y.leftCols(nb).noalias() = DMAT_here * phi.leftCols(nb);
310 for (
Index p = 0; p < nb; ++p) {
311 const double r = 0.5 * phi.col(p).dot(y.col(p));
312 if (r * weights[start + p] < 1.e-20) {
315 const Eigen::Vector3d g =
316 dphi.middleCols(3 * p, 3).transpose() * y.col(p);
319 sigma.push_back(g.squaredNorm());
334 for (
Index k = 0; k < nk; ++k) {
335 const Index p = kept[k];
336 const double w = weights[start + p];
337 EXC_box += w * rho[k] * exc[k];
338 a.col(k) = (w * 0.5 * vrho[k]) * phi.col(p);
340 a.col(k).noalias() +=
341 (w * 2.0 * vsigma[k]) * (dphi.middleCols(3 * p, 3) * grad[k]);
344 phi.col(k) = phi.col(p);
347 Vxc_here.noalias() += a.leftCols(nk) * phi.leftCols(nk).transpose();
402 const Eigen::MatrixXd& density_matrix,
const AOBasis& dftbasis)
const {
403 assert(density_matrix.isApprox(density_matrix.transpose()) &&
404 "Density matrix has to be symmetric!");
408 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
409 Eigen::MatrixXd::Zero(natoms, 3));
411 std::exception_ptr eptr_pulay =
nullptr;
412#pragma omp parallel for schedule(guided)
413 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
421 const Eigen::MatrixXd DMAT_here =
424 double cutoff = 1.e-40 / double(density_matrix.rows()) /
425 double(density_matrix.rows());
426 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
434 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
435 const std::vector<const AOShell*>& shells = box.
getShells();
436 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
437 for (
size_t s = 0; s < shells.size(); ++s) {
438 Index atom = shells[s]->getAtomIndex();
439 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
440 local_idx_to_atom[ao_ranges[s].start + k] = atom;
444 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
455 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
456 double rho = 0.5 * temp.dot(ao.
values);
457 const double weight = weights[p];
459 if (rho * weight < 1.e-20) {
463 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
503 Eigen::MatrixX3d Gmat = DMAT_here * ao.
derivatives;
504 Eigen::VectorXd s_vec = Gmat * rho_grad;
506 Eigen::Matrix3d Hessian_rho = Eigen::Matrix3d::Zero();
508 Hessian_rho += temp(mu) * ao.
hessians[mu];
510 Eigen::Matrix3d M = ao.
derivatives.transpose() * Gmat;
511 Hessian_rho += 0.5 * (M + M.transpose());
513 Index owner_of_point_sigma = owner_atoms[p];
514 Eigen::Vector3d dsigma_translation = 2.0 * (Hessian_rho * rho_grad);
515 grad_thread[thread_id].row(owner_of_point_sigma) +=
516 (weight * xc.
df_dsigma * dsigma_translation).transpose();
557 Index owner_of_point = owner_atoms[p];
558 grad_thread[thread_id].row(owner_of_point) +=
559 (weight * xc.
df_drho * rho_grad).transpose();
569 Index atom = local_idx_to_atom[mu];
570 Eigen::Vector3d contribution = -weight * xc.
df_drho * temp(mu) *
575 Eigen::Vector3d dsigma_basis_mu =
576 -2.0 * (ao.
derivatives.row(mu).transpose() * s_vec(mu) +
577 temp(mu) * (ao.
hessians[mu] * rho_grad));
578 contribution += weight * xc.
df_dsigma * dsigma_basis_mu;
579 grad_thread[thread_id].row(atom) += contribution.transpose();
586 eptr_pulay = std::current_exception();
592 std::rethrow_exception(eptr_pulay);
595 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
596 for (
Index t = 0; t < nthreads; ++t) {
597 grad += grad_thread[t];
606 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta)
const {
607 assert(dmat_alpha.isApprox(dmat_alpha.transpose()) &&
608 "Alpha density matrix has to be symmetric!");
609 assert(dmat_beta.isApprox(dmat_beta.transpose()) &&
610 "Beta density matrix has to be symmetric!");
614 Eigen::MatrixXd::Zero(dmat_alpha.rows(), dmat_alpha.cols());
615 result.
vxc_beta = Eigen::MatrixXd::Zero(dmat_beta.rows(), dmat_beta.cols());
619 Eigen::MatrixXd vxc_alpha_private =
620 Eigen::MatrixXd::Zero(dmat_alpha.rows(), dmat_alpha.cols());
621 Eigen::MatrixXd vxc_beta_private =
622 Eigen::MatrixXd::Zero(dmat_beta.rows(), dmat_beta.cols());
623 double exc_private = 0.0;
625 std::vector<Index> kept;
626 std::vector<double> rho, sigma, exc, vrho, vsigma;
627 std::vector<Eigen::Vector3d> grad_a, grad_b;
629#pragma omp for schedule(guided)
630 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
640 1.e-40 / double(dmat_alpha.rows()) / double(dmat_alpha.rows());
641 if (std::max(DMa.cwiseAbs2().maxCoeff(), DMb.cwiseAbs2().maxCoeff()) <
648 Eigen::MatrixXd Vxc_a_here = Eigen::MatrixXd::Zero(nf, nf);
649 Eigen::MatrixXd Vxc_b_here = Eigen::MatrixXd::Zero(nf, nf);
650 Eigen::MatrixXd phi(nf, block);
651 Eigen::MatrixXd dphi(nf, 3 * block);
652 Eigen::MatrixXd ya(nf, block);
653 Eigen::MatrixXd yb(nf, block);
654 Eigen::MatrixXd aa(nf, block);
655 Eigen::MatrixXd ab(nf, block);
657 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
660 for (
Index start = 0; start < box.
size(); start += block) {
661 const Index nb = std::min(block, box.
size() - start);
662 for (
Index p = 0; p < nb; ++p) {
665 ya.leftCols(nb).noalias() = DMa * phi.leftCols(nb);
666 yb.leftCols(nb).noalias() = DMb * phi.leftCols(nb);
673 for (
Index p = 0; p < nb; ++p) {
674 const double rho_a = phi.col(p).dot(ya.col(p));
675 const double rho_b = phi.col(p).dot(yb.col(p));
676 if ((rho_a + rho_b) * weights[start + p] < 1.e-20) {
679 const Eigen::Vector3d ga =
680 2.0 * (dphi.middleCols(3 * p, 3).transpose() * ya.col(p));
681 const Eigen::Vector3d gb =
682 2.0 * (dphi.middleCols(3 * p, 3).transpose() * yb.col(p));
684 rho.push_back(rho_a);
685 rho.push_back(rho_b);
686 sigma.push_back(ga.dot(ga));
687 sigma.push_back(ga.dot(gb));
688 sigma.push_back(gb.dot(gb));
689 grad_a.push_back(ga);
690 grad_b.push_back(gb);
698 vsigma.resize(3 * nk);
700 vrho.data(), vsigma.data());
702 for (
Index k = 0; k < nk; ++k) {
703 const Index p = kept[k];
704 const double w = weights[start + p];
705 exc_private += w * (rho[2 * k] + rho[2 * k + 1]) * exc[k];
707 aa.col(k) = (w * 0.5 * vrho[2 * k]) * phi.col(p);
708 ab.col(k) = (w * 0.5 * vrho[2 * k + 1]) * phi.col(p);
710 const auto d = dphi.middleCols(3 * p, 3);
711 const Eigen::VectorXd g_a = d * grad_a[k];
712 const Eigen::VectorXd g_b = d * grad_b[k];
713 const double vs_aa = vsigma[3 * k];
714 const double vs_ab = vsigma[3 * k + 1];
715 const double vs_bb = vsigma[3 * k + 2];
716 aa.col(k).noalias() += w * (2.0 * vs_aa * g_a + vs_ab * g_b);
717 ab.col(k).noalias() += w * (vs_ab * g_a + 2.0 * vs_bb * g_b);
720 phi.col(k) = phi.col(p);
723 Vxc_a_here.noalias() += aa.leftCols(nk) * phi.leftCols(nk).transpose();
724 Vxc_b_here.noalias() += ab.leftCols(nk) * phi.leftCols(nk).transpose();
733 result.
vxc_alpha += vxc_alpha_private + vxc_alpha_private.transpose();
734 result.
vxc_beta += vxc_beta_private + vxc_beta_private.transpose();
735 result.
energy += exc_private;
785 const Eigen::MatrixXd& density_matrix,
const QMMolecule& atoms)
const {
787 Eigen::MatrixXd Rij =
grid_.CalcInverseAtomDist(atoms);
790 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
791 Eigen::MatrixXd::Zero(natoms, 3));
793 std::exception_ptr eptr_weight =
nullptr;
794#pragma omp parallel for schedule(guided)
795 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
803 const Eigen::MatrixXd DMAT_here =
805 double cutoff = 1.e-40 / double(density_matrix.rows()) /
806 double(density_matrix.rows());
807 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
811 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
815 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
817 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
818 double rho = 0.5 * temp.dot(ao.
values);
819 double weight = weights[pidx];
820 if (rho * weight < 1.e-20) {
823 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
827 Index owner = owner_atoms[pidx];
835 throw std::runtime_error(
836 "GridWeightGradient: grid point has no owner_atom set -- was "
837 "this grid built via GridSetup after the owner-atom tracking "
844 const Eigen::Vector3d& point = points[pidx];
845 Eigen::VectorXd rq(natoms);
846 for (
Index k = 0; k < natoms; ++k) {
847 rq(k) = (point - atoms[k].
getPos()).norm();
854 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
855 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
856 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
860 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
861 for (
Index ii = 1; ii < natoms; ++ii) {
862 for (
Index jj = 0; jj < ii; ++jj) {
863 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
864 mu_table(jj, ii) = mu;
865 if (mu > kSSWCutoff) {
868 }
else if (mu < -kSSWCutoff) {
872 double sk = SSWValue(mu);
873 sk_table(jj, ii) = sk;
879 double wsum = p.sum();
880 double w_owner = p(owner) / wsum;
886 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
887 if (A == owner && A == k) {
888 return Eigen::Vector3d::Zero();
889 }
else if (A == owner) {
890 return (point - atoms[k].getPos()) / rq(k);
892 return -(point - atoms[k].
getPos()) / rq(k);
894 return Eigen::Vector3d::Zero();
897 Eigen::Vector3d rvec = atoms[a].
getPos() - atoms[b].
getPos();
898 double Rab = rvec.norm();
904 return Eigen::Vector3d::Zero();
908 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
909 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
910 double Rab = 1.0 / Rij(a, b);
911 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
912 double mu = mu_table(a, b);
913 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
915 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
928 constexpr double kNegligibleP = 1.e-8;
929 if (p(k) < kNegligibleP) {
930 return Eigen::Vector3d::Zero();
932 Eigen::Vector3d total = Eigen::Vector3d::Zero();
933 for (
Index b = k + 1; b < natoms; ++b) {
934 if (hard(k, b) != 0) {
937 double skv = sk_table(k, b);
938 if (skv < kNegligibleP) {
943 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
945 for (
Index a = 0; a < k; ++a) {
946 if (hard(a, k) != 0) {
949 double skv = sk_table(a, k);
950 double one_minus_skv = 1.0 - skv;
951 if (one_minus_skv < kNegligibleP) {
954 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
970 constexpr double kNegligibleWOwner = 1.e-8;
971 if (w_owner < kNegligibleWOwner) {
991 double C_p = weight / w_owner;
993 double prefactor = C_p * rho * xc.
f_xc;
995 for (
Index A = 0; A < natoms; ++A) {
996 Eigen::Vector3d dp_owner = dp_dR(owner, A);
997 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
998 for (
Index k = 0; k < natoms; ++k) {
999 dwsum += dp_dR(k, A);
1001 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
1002 Eigen::Vector3d contribution = prefactor * dw;
1003 grad_thread[thread_id].row(A) += contribution.transpose();
1010 eptr_weight = std::current_exception();
1016 std::rethrow_exception(eptr_weight);
1019 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1020 for (
Index t = 0; t < nthreads; ++t) {
1021 grad += grad_thread[t];
1028 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
1029 const AOBasis& dftbasis)
const {
1043 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1044 Eigen::MatrixXd::Zero(natoms, 3));
1046 std::exception_ptr eptr_pulay_uks =
nullptr;
1047#pragma omp parallel for schedule(guided)
1048 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1064 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
1065 const std::vector<const AOShell*>& shells = box.
getShells();
1066 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
1067 for (
size_t s = 0; s < shells.size(); ++s) {
1068 Index atom = shells[s]->getAtomIndex();
1069 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
1070 local_idx_to_atom[ao_ranges[s].start + k] = atom;
1073 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1075 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1078 for (
Index p = 0; p < box.
size(); ++p) {
1081 Eigen::VectorXd temp_a = DMa * ao.
values;
1082 Eigen::VectorXd temp_b = DMb * ao.
values;
1083 const double rho_a = ao.
values.dot(temp_a);
1084 const double rho_b = ao.
values.dot(temp_b);
1085 const double rho = rho_a + rho_b;
1086 const double weight = weights[p];
1088 if (rho * weight < 1.e-20) {
1092 const Eigen::Vector3d rho_a_grad =
1094 const Eigen::Vector3d rho_b_grad =
1096 const double sigma_aa = rho_a_grad.dot(rho_a_grad);
1097 const double sigma_ab = rho_a_grad.dot(rho_b_grad);
1098 const double sigma_bb = rho_b_grad.dot(rho_b_grad);
1105 Index owner_of_point = owner_atoms[p];
1106 grad_thread[thread_id].row(owner_of_point) +=
1107 (weight * (xc.
vrho_a * rho_a_grad + xc.
vrho_b * rho_b_grad))
1115 Eigen::MatrixX3d Gmat_a = 2.0 * (DMa * ao.
derivatives);
1116 Eigen::MatrixX3d Gmat_b = 2.0 * (DMb * ao.
derivatives);
1117 Eigen::Vector3d V_a =
1119 Eigen::Vector3d V_b =
1124 Eigen::Matrix3d Hessian_rho_a = Eigen::Matrix3d::Zero();
1125 Eigen::Matrix3d Hessian_rho_b = Eigen::Matrix3d::Zero();
1127 Hessian_rho_a += 2.0 * temp_a(mu) * ao.
hessians[mu];
1128 Hessian_rho_b += 2.0 * temp_b(mu) * ao.
hessians[mu];
1130 Eigen::Matrix3d Ma = ao.
derivatives.transpose() * Gmat_a;
1131 Eigen::Matrix3d Mb = ao.
derivatives.transpose() * Gmat_b;
1132 Hessian_rho_a += 0.5 * (Ma + Ma.transpose());
1133 Hessian_rho_b += 0.5 * (Mb + Mb.transpose());
1135 grad_thread[thread_id].row(owner_of_point) +=
1136 (weight * (Hessian_rho_a * V_a + Hessian_rho_b * V_b)).transpose();
1140 Eigen::VectorXd Gmat_a_dot_Va = Gmat_a * V_a;
1141 Eigen::VectorXd Gmat_b_dot_Vb = Gmat_b * V_b;
1143 Index atom = local_idx_to_atom[mu];
1144 Eigen::Vector3d lda_contribution =
1148 Eigen::Vector3d sigma_contribution =
1150 (ao.
derivatives.row(mu).transpose() * Gmat_a_dot_Va(mu) +
1151 2.0 * temp_a(mu) * (ao.
hessians[mu] * V_a) +
1152 ao.
derivatives.row(mu).transpose() * Gmat_b_dot_Vb(mu) +
1153 2.0 * temp_b(mu) * (ao.
hessians[mu] * V_b));
1154 grad_thread[thread_id].row(atom) +=
1155 (lda_contribution + sigma_contribution).transpose();
1161 if (!eptr_pulay_uks) {
1162 eptr_pulay_uks = std::current_exception();
1167 if (eptr_pulay_uks) {
1168 std::rethrow_exception(eptr_pulay_uks);
1171 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1172 for (
Index t = 0; t < nthreads; ++t) {
1173 grad += grad_thread[t];
1180 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
1199 Eigen::MatrixXd Rij =
grid_.CalcInverseAtomDist(atoms);
1202 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1203 Eigen::MatrixXd::Zero(natoms, 3));
1205 std::exception_ptr eptr_weight_uks =
nullptr;
1206#pragma omp parallel for schedule(guided)
1207 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1218 1.e-40 / double(dmat_alpha.rows()) / double(dmat_alpha.rows());
1219 if (std::max(DMa.cwiseAbs2().maxCoeff(), DMb.cwiseAbs2().maxCoeff()) <
1224 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1226 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1228 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
1230 Eigen::VectorXd temp_a = DMa * ao.
values;
1231 Eigen::VectorXd temp_b = DMb * ao.
values;
1232 const double rho_a = ao.
values.dot(temp_a);
1233 const double rho_b = ao.
values.dot(temp_b);
1234 const double rho = rho_a + rho_b;
1235 double weight = weights[pidx];
1236 if (rho * weight < 1.e-20) {
1239 const Eigen::Vector3d rho_a_grad =
1241 const Eigen::Vector3d rho_b_grad =
1243 const double sigma_aa = rho_a_grad.dot(rho_a_grad);
1244 const double sigma_ab = rho_a_grad.dot(rho_b_grad);
1245 const double sigma_bb = rho_b_grad.dot(rho_b_grad);
1249 Index owner = owner_atoms[pidx];
1251 throw std::runtime_error(
1252 "GridWeightGradientUKS: grid point has no owner_atom set -- "
1253 "was this grid built via GridSetup after the owner-atom "
1254 "tracking change?");
1257 const Eigen::Vector3d& point = points[pidx];
1258 Eigen::VectorXd rq(natoms);
1259 for (
Index k = 0; k < natoms; ++k) {
1260 rq(k) = (point - atoms[k].
getPos()).norm();
1263 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
1264 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
1265 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
1266 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
1267 for (
Index ii = 1; ii < natoms; ++ii) {
1268 for (
Index jj = 0; jj < ii; ++jj) {
1269 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
1270 mu_table(jj, ii) = mu;
1271 if (mu > kSSWCutoff) {
1274 }
else if (mu < -kSSWCutoff) {
1278 double sk = SSWValue(mu);
1279 sk_table(jj, ii) = sk;
1281 p(ii) *= (1.0 - sk);
1285 double wsum = p.sum();
1286 double w_owner = p(owner) / wsum;
1288 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1289 if (A == owner && A == k) {
1290 return Eigen::Vector3d::Zero();
1291 }
else if (A == owner) {
1292 return (point - atoms[k].getPos()) / rq(k);
1293 }
else if (A == k) {
1294 return -(point - atoms[k].
getPos()) / rq(k);
1296 return Eigen::Vector3d::Zero();
1299 Eigen::Vector3d rvec = atoms[a].
getPos() - atoms[b].
getPos();
1300 double Rab = rvec.norm();
1303 }
else if (A == b) {
1306 return Eigen::Vector3d::Zero();
1309 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
1310 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
1311 double Rab = 1.0 / Rij(a, b);
1312 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
1313 double mu = mu_table(a, b);
1314 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
1316 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1317 constexpr double kNegligibleP = 1.e-8;
1318 if (p(k) < kNegligibleP) {
1319 return Eigen::Vector3d::Zero();
1321 Eigen::Vector3d total = Eigen::Vector3d::Zero();
1322 for (
Index b = k + 1; b < natoms; ++b) {
1323 if (hard(k, b) != 0) {
1326 double skv = sk_table(k, b);
1327 if (skv < kNegligibleP) {
1330 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
1332 for (
Index a = 0; a < k; ++a) {
1333 if (hard(a, k) != 0) {
1336 double skv = sk_table(a, k);
1337 double one_minus_skv = 1.0 - skv;
1338 if (one_minus_skv < kNegligibleP) {
1341 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
1344 return p(k) * total;
1347 constexpr double kNegligibleWOwner = 1.e-8;
1348 if (w_owner < kNegligibleWOwner) {
1351 double C_p = weight / w_owner;
1352 double prefactor = C_p * rho * xc.
f_xc;
1354 for (
Index A = 0; A < natoms; ++A) {
1355 Eigen::Vector3d dp_owner = dp_dR(owner, A);
1356 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
1357 for (
Index k = 0; k < natoms; ++k) {
1358 dwsum += dp_dR(k, A);
1360 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
1361 Eigen::Vector3d contribution = prefactor * dw;
1362 grad_thread[thread_id].row(A) += contribution.transpose();
1368 if (!eptr_weight_uks) {
1369 eptr_weight_uks = std::current_exception();
1374 if (eptr_weight_uks) {
1375 std::rethrow_exception(eptr_weight_uks);
1378 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1379 for (
Index t = 0; t < nthreads; ++t) {
1380 grad += grad_thread[t];