55 double exactexchange = 0.0;
58 std::vector<std::string> functional_names =
61 if (functional_names.size() > 2) {
62 throw std::runtime_error(
"Too many functional names");
63 }
else if (functional_names.empty()) {
64 throw std::runtime_error(
"Specify at least one functional");
67 for (
const std::string& functional_name : functional_names) {
68 int func_id = map.getID(functional_name);
75 if (xc_func_init(&func, func_id, XC_UNPOLARIZED) != 0) {
76 throw std::runtime_error(
77 (boost::format(
"Functional %s not found\n") % functional_name).str());
80 if (exactexchange > 0 && func.cam_alpha > 0) {
82 throw std::runtime_error(
83 "You have specified two functionals with exact exchange");
86 exactexchange += func.cam_alpha;
193 double rho_a,
double rho_b,
double sigma_aa,
double sigma_ab,
194 double sigma_bb)
const {
199 xc_func_type xfunc_pol;
200 if (xc_func_init(&xfunc_pol,
xfunc_id, XC_POLARIZED) != 0) {
201 throw std::runtime_error(
202 "Failed to initialize polarized exchange XC "
203 "functional in EvaluateXCSpin.");
206 xc_func_type cfunc_pol;
207 bool cfunc_pol_init =
false;
209 if (xc_func_init(&cfunc_pol,
cfunc_id, XC_POLARIZED) != 0) {
210 xc_func_end(&xfunc_pol);
211 throw std::runtime_error(
212 "Failed to initialize polarized correlation XC "
213 "functional in EvaluateXCSpin.");
215 cfunc_pol_init =
true;
218 double rho[2] = {rho_a, rho_b};
220 switch (xfunc_pol.info->family) {
221 case XC_FAMILY_LDA: {
222 double vrho[2] = {0.0, 0.0};
223 xc_lda_exc_vxc(&xfunc_pol, 1, rho, &result.
f_xc, vrho);
229 case XC_FAMILY_HYB_GGA: {
230 double sigma[3] = {sigma_aa, sigma_ab, sigma_bb};
231 double vrho[2] = {0.0, 0.0};
232 double vsigma[3] = {0.0, 0.0, 0.0};
233 xc_gga_exc_vxc(&xfunc_pol, 1, rho, sigma, &result.
f_xc, vrho, vsigma);
242 xc_func_end(&xfunc_pol);
243 if (cfunc_pol_init) {
244 xc_func_end(&cfunc_pol);
246 throw std::runtime_error(
"Unsupported XC family for polarized DFT.");
252 switch (cfunc_pol.info->family) {
253 case XC_FAMILY_LDA: {
254 double vrho[2] = {0.0, 0.0};
255 xc_lda_exc_vxc(&cfunc_pol, 1, rho, &temp.
f_xc, vrho);
261 case XC_FAMILY_HYB_GGA: {
262 double sigma[3] = {sigma_aa, sigma_ab, sigma_bb};
263 double vrho[2] = {0.0, 0.0};
264 double vsigma[3] = {0.0, 0.0, 0.0};
265 xc_gga_exc_vxc(&cfunc_pol, 1, rho, sigma, &temp.
f_xc, vrho, vsigma);
274 xc_func_end(&xfunc_pol);
275 xc_func_end(&cfunc_pol);
276 throw std::runtime_error(
277 "Unsupported correlation family for polarized DFT.");
288 xc_func_end(&xfunc_pol);
289 if (cfunc_pol_init) {
290 xc_func_end(&cfunc_pol);
298 const Eigen::MatrixXd& density_matrix)
const {
299 assert(density_matrix.isApprox(density_matrix.transpose()) &&
300 "Density matrix has to be symmetric!");
304#pragma omp parallel for schedule(guided) reduction(+ : vxc)
305 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
311 double EXC_box = 0.0;
317 1.e-40 / double(density_matrix.rows()) / double(density_matrix.rows());
318 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
322 Eigen::MatrixXd Vxc_here =
323 Eigen::MatrixXd::Zero(DMAT_here.rows(), DMAT_here.cols());
325 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
331 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
332 double rho = 0.5 * temp.dot(ao.
values);
333 const double weight = weights[p];
335 if (rho * weight < 1.e-20) {
339 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
344 EXC_box += weight * rho * xc.
f_xc;
349 Vxc_here.noalias() += temp * ao.
values.transpose();
404 const Eigen::MatrixXd& density_matrix,
const AOBasis& dftbasis)
const {
405 assert(density_matrix.isApprox(density_matrix.transpose()) &&
406 "Density matrix has to be symmetric!");
410 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
411 Eigen::MatrixXd::Zero(natoms, 3));
413 std::exception_ptr eptr_pulay =
nullptr;
414#pragma omp parallel for schedule(guided)
415 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
423 const Eigen::MatrixXd DMAT_here =
426 double cutoff = 1.e-40 / double(density_matrix.rows()) /
427 double(density_matrix.rows());
428 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
436 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
437 const std::vector<const AOShell*>& shells = box.
getShells();
438 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
439 for (
size_t s = 0; s < shells.size(); ++s) {
440 Index atom = shells[s]->getAtomIndex();
441 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
442 local_idx_to_atom[ao_ranges[s].start + k] = atom;
446 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
457 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
458 double rho = 0.5 * temp.dot(ao.
values);
459 const double weight = weights[p];
461 if (rho * weight < 1.e-20) {
465 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
505 Eigen::MatrixX3d Gmat = DMAT_here * ao.
derivatives;
506 Eigen::VectorXd s_vec = Gmat * rho_grad;
508 Eigen::Matrix3d Hessian_rho = Eigen::Matrix3d::Zero();
510 Hessian_rho += temp(mu) * ao.
hessians[mu];
512 Eigen::Matrix3d M = ao.
derivatives.transpose() * Gmat;
513 Hessian_rho += 0.5 * (M + M.transpose());
515 Index owner_of_point_sigma = owner_atoms[p];
516 Eigen::Vector3d dsigma_translation = 2.0 * (Hessian_rho * rho_grad);
517 grad_thread[thread_id].row(owner_of_point_sigma) +=
518 (weight * xc.
df_dsigma * dsigma_translation).transpose();
559 Index owner_of_point = owner_atoms[p];
560 grad_thread[thread_id].row(owner_of_point) +=
561 (weight * xc.
df_drho * rho_grad).transpose();
571 Index atom = local_idx_to_atom[mu];
572 Eigen::Vector3d contribution = -weight * xc.
df_drho * temp(mu) *
577 Eigen::Vector3d dsigma_basis_mu =
578 -2.0 * (ao.
derivatives.row(mu).transpose() * s_vec(mu) +
579 temp(mu) * (ao.
hessians[mu] * rho_grad));
580 contribution += weight * xc.
df_dsigma * dsigma_basis_mu;
581 grad_thread[thread_id].row(atom) += contribution.transpose();
588 eptr_pulay = std::current_exception();
594 std::rethrow_exception(eptr_pulay);
597 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
598 for (
Index t = 0; t < nthreads; ++t) {
599 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#pragma omp for schedule(guided)
626 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
636 1.e-40 / double(dmat_alpha.rows()) / double(dmat_alpha.rows());
637 if (std::max(DMa.cwiseAbs2().maxCoeff(), DMb.cwiseAbs2().maxCoeff()) <
642 Eigen::MatrixXd Vxc_a_here =
643 Eigen::MatrixXd::Zero(DMa.rows(), DMa.cols());
644 Eigen::MatrixXd Vxc_b_here =
645 Eigen::MatrixXd::Zero(DMb.rows(), DMb.cols());
647 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
653 Eigen::VectorXd temp_a = DMa * ao.
values;
654 Eigen::VectorXd temp_b = DMb * ao.
values;
656 const double rho_a = ao.
values.dot(temp_a);
657 const double rho_b = ao.
values.dot(temp_b);
658 const double rho = rho_a + rho_b;
659 const double weight = weights[p];
661 if (rho * weight < 1.e-20) {
667 const Eigen::Vector3d grad_a =
669 const Eigen::Vector3d grad_b =
672 const double sigma_aa = grad_a.dot(grad_a);
673 const double sigma_ab = grad_a.dot(grad_b);
674 const double sigma_bb = grad_b.dot(grad_b);
679 exc_private += weight * rho * xc.
f_xc;
681 if (
xfunc.info->family == XC_FAMILY_LDA) {
683 Eigen::VectorXd wa = weight * (0.5 * xc.
vrho_a) * ao.
values;
684 Eigen::VectorXd wb = weight * (0.5 * xc.
vrho_b) * ao.
values;
686 Vxc_a_here.noalias() += wa * ao.
values.transpose();
687 Vxc_b_here.noalias() += wb * ao.
values.transpose();
701 Vxc_a_here.noalias() += wa * ao.
values.transpose();
702 Vxc_b_here.noalias() += wb * ao.
values.transpose();
712 result.
vxc_alpha += vxc_alpha_private + vxc_alpha_private.transpose();
713 result.
vxc_beta += vxc_beta_private + vxc_beta_private.transpose();
714 result.
energy += exc_private;
764 const Eigen::MatrixXd& density_matrix,
const QMMolecule& atoms)
const {
766 Eigen::MatrixXd Rij =
grid_.CalcInverseAtomDist(atoms);
769 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
770 Eigen::MatrixXd::Zero(natoms, 3));
772 std::exception_ptr eptr_weight =
nullptr;
773#pragma omp parallel for schedule(guided)
774 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
782 const Eigen::MatrixXd DMAT_here =
784 double cutoff = 1.e-40 / double(density_matrix.rows()) /
785 double(density_matrix.rows());
786 if (DMAT_here.cwiseAbs2().maxCoeff() < cutoff) {
790 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
794 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
796 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
797 double rho = 0.5 * temp.dot(ao.
values);
798 double weight = weights[pidx];
799 if (rho * weight < 1.e-20) {
802 const Eigen::Vector3d rho_grad = temp.transpose() * ao.
derivatives;
806 Index owner = owner_atoms[pidx];
814 throw std::runtime_error(
815 "GridWeightGradient: grid point has no owner_atom set -- was "
816 "this grid built via GridSetup after the owner-atom tracking "
823 const Eigen::Vector3d& point = points[pidx];
824 Eigen::VectorXd rq(natoms);
825 for (
Index k = 0; k < natoms; ++k) {
826 rq(k) = (point - atoms[k].
getPos()).norm();
833 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
834 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
835 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
839 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
840 for (
Index ii = 1; ii < natoms; ++ii) {
841 for (
Index jj = 0; jj < ii; ++jj) {
842 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
843 mu_table(jj, ii) = mu;
844 if (mu > kSSWCutoff) {
847 }
else if (mu < -kSSWCutoff) {
851 double sk = SSWValue(mu);
852 sk_table(jj, ii) = sk;
858 double wsum = p.sum();
859 double w_owner = p(owner) / wsum;
865 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
866 if (A == owner && A == k) {
867 return Eigen::Vector3d::Zero();
868 }
else if (A == owner) {
869 return (point - atoms[k].getPos()) / rq(k);
871 return -(point - atoms[k].
getPos()) / rq(k);
873 return Eigen::Vector3d::Zero();
876 Eigen::Vector3d rvec = atoms[a].
getPos() - atoms[b].
getPos();
877 double Rab = rvec.norm();
883 return Eigen::Vector3d::Zero();
887 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
888 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
889 double Rab = 1.0 / Rij(a, b);
890 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
891 double mu = mu_table(a, b);
892 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
894 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
907 constexpr double kNegligibleP = 1.e-8;
908 if (p(k) < kNegligibleP) {
909 return Eigen::Vector3d::Zero();
911 Eigen::Vector3d total = Eigen::Vector3d::Zero();
912 for (
Index b = k + 1; b < natoms; ++b) {
913 if (hard(k, b) != 0) {
916 double skv = sk_table(k, b);
917 if (skv < kNegligibleP) {
922 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
924 for (
Index a = 0; a < k; ++a) {
925 if (hard(a, k) != 0) {
928 double skv = sk_table(a, k);
929 double one_minus_skv = 1.0 - skv;
930 if (one_minus_skv < kNegligibleP) {
933 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
949 constexpr double kNegligibleWOwner = 1.e-8;
950 if (w_owner < kNegligibleWOwner) {
970 double C_p = weight / w_owner;
972 double prefactor = C_p * rho * xc.
f_xc;
974 for (
Index A = 0; A < natoms; ++A) {
975 Eigen::Vector3d dp_owner = dp_dR(owner, A);
976 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
977 for (
Index k = 0; k < natoms; ++k) {
978 dwsum += dp_dR(k, A);
980 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
981 Eigen::Vector3d contribution = prefactor * dw;
982 grad_thread[thread_id].row(A) += contribution.transpose();
989 eptr_weight = std::current_exception();
995 std::rethrow_exception(eptr_weight);
998 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
999 for (
Index t = 0; t < nthreads; ++t) {
1000 grad += grad_thread[t];
1007 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
1008 const AOBasis& dftbasis)
const {
1022 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1023 Eigen::MatrixXd::Zero(natoms, 3));
1025 std::exception_ptr eptr_pulay_uks =
nullptr;
1026#pragma omp parallel for schedule(guided)
1027 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1043 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
1044 const std::vector<const AOShell*>& shells = box.
getShells();
1045 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
1046 for (
size_t s = 0; s < shells.size(); ++s) {
1047 Index atom = shells[s]->getAtomIndex();
1048 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
1049 local_idx_to_atom[ao_ranges[s].start + k] = atom;
1052 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1054 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1057 for (
Index p = 0; p < box.
size(); ++p) {
1060 Eigen::VectorXd temp_a = DMa * ao.
values;
1061 Eigen::VectorXd temp_b = DMb * ao.
values;
1062 const double rho_a = ao.
values.dot(temp_a);
1063 const double rho_b = ao.
values.dot(temp_b);
1064 const double rho = rho_a + rho_b;
1065 const double weight = weights[p];
1067 if (rho * weight < 1.e-20) {
1071 const Eigen::Vector3d rho_a_grad =
1073 const Eigen::Vector3d rho_b_grad =
1075 const double sigma_aa = rho_a_grad.dot(rho_a_grad);
1076 const double sigma_ab = rho_a_grad.dot(rho_b_grad);
1077 const double sigma_bb = rho_b_grad.dot(rho_b_grad);
1084 Index owner_of_point = owner_atoms[p];
1085 grad_thread[thread_id].row(owner_of_point) +=
1086 (weight * (xc.
vrho_a * rho_a_grad + xc.
vrho_b * rho_b_grad))
1094 Eigen::MatrixX3d Gmat_a = 2.0 * (DMa * ao.
derivatives);
1095 Eigen::MatrixX3d Gmat_b = 2.0 * (DMb * ao.
derivatives);
1096 Eigen::Vector3d V_a =
1098 Eigen::Vector3d V_b =
1103 Eigen::Matrix3d Hessian_rho_a = Eigen::Matrix3d::Zero();
1104 Eigen::Matrix3d Hessian_rho_b = Eigen::Matrix3d::Zero();
1106 Hessian_rho_a += 2.0 * temp_a(mu) * ao.
hessians[mu];
1107 Hessian_rho_b += 2.0 * temp_b(mu) * ao.
hessians[mu];
1109 Eigen::Matrix3d Ma = ao.
derivatives.transpose() * Gmat_a;
1110 Eigen::Matrix3d Mb = ao.
derivatives.transpose() * Gmat_b;
1111 Hessian_rho_a += 0.5 * (Ma + Ma.transpose());
1112 Hessian_rho_b += 0.5 * (Mb + Mb.transpose());
1114 grad_thread[thread_id].row(owner_of_point) +=
1115 (weight * (Hessian_rho_a * V_a + Hessian_rho_b * V_b)).transpose();
1119 Eigen::VectorXd Gmat_a_dot_Va = Gmat_a * V_a;
1120 Eigen::VectorXd Gmat_b_dot_Vb = Gmat_b * V_b;
1122 Index atom = local_idx_to_atom[mu];
1123 Eigen::Vector3d lda_contribution =
1127 Eigen::Vector3d sigma_contribution =
1129 (ao.
derivatives.row(mu).transpose() * Gmat_a_dot_Va(mu) +
1130 2.0 * temp_a(mu) * (ao.
hessians[mu] * V_a) +
1131 ao.
derivatives.row(mu).transpose() * Gmat_b_dot_Vb(mu) +
1132 2.0 * temp_b(mu) * (ao.
hessians[mu] * V_b));
1133 grad_thread[thread_id].row(atom) +=
1134 (lda_contribution + sigma_contribution).transpose();
1140 if (!eptr_pulay_uks) {
1141 eptr_pulay_uks = std::current_exception();
1146 if (eptr_pulay_uks) {
1147 std::rethrow_exception(eptr_pulay_uks);
1150 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1151 for (
Index t = 0; t < nthreads; ++t) {
1152 grad += grad_thread[t];
1159 const Eigen::MatrixXd& dmat_alpha,
const Eigen::MatrixXd& dmat_beta,
1178 Eigen::MatrixXd Rij =
grid_.CalcInverseAtomDist(atoms);
1181 std::vector<Eigen::MatrixXd> grad_thread(nthreads,
1182 Eigen::MatrixXd::Zero(natoms, 3));
1184 std::exception_ptr eptr_weight_uks =
nullptr;
1185#pragma omp parallel for schedule(guided)
1186 for (
Index i = 0; i <
grid_.getBoxesSize(); ++i) {
1197 1.e-40 / double(dmat_alpha.rows()) / double(dmat_alpha.rows());
1198 if (std::max(DMa.cwiseAbs2().maxCoeff(), DMb.cwiseAbs2().maxCoeff()) <
1203 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
1205 const std::vector<Index>& owner_atoms = box.
getOwnerAtoms();
1207 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
1209 Eigen::VectorXd temp_a = DMa * ao.
values;
1210 Eigen::VectorXd temp_b = DMb * ao.
values;
1211 const double rho_a = ao.
values.dot(temp_a);
1212 const double rho_b = ao.
values.dot(temp_b);
1213 const double rho = rho_a + rho_b;
1214 double weight = weights[pidx];
1215 if (rho * weight < 1.e-20) {
1218 const Eigen::Vector3d rho_a_grad =
1220 const Eigen::Vector3d rho_b_grad =
1222 const double sigma_aa = rho_a_grad.dot(rho_a_grad);
1223 const double sigma_ab = rho_a_grad.dot(rho_b_grad);
1224 const double sigma_bb = rho_b_grad.dot(rho_b_grad);
1228 Index owner = owner_atoms[pidx];
1230 throw std::runtime_error(
1231 "GridWeightGradientUKS: grid point has no owner_atom set -- "
1232 "was this grid built via GridSetup after the owner-atom "
1233 "tracking change?");
1236 const Eigen::Vector3d& point = points[pidx];
1237 Eigen::VectorXd rq(natoms);
1238 for (
Index k = 0; k < natoms; ++k) {
1239 rq(k) = (point - atoms[k].
getPos()).norm();
1242 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
1243 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
1244 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
1245 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
1246 for (
Index ii = 1; ii < natoms; ++ii) {
1247 for (
Index jj = 0; jj < ii; ++jj) {
1248 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
1249 mu_table(jj, ii) = mu;
1250 if (mu > kSSWCutoff) {
1253 }
else if (mu < -kSSWCutoff) {
1257 double sk = SSWValue(mu);
1258 sk_table(jj, ii) = sk;
1260 p(ii) *= (1.0 - sk);
1264 double wsum = p.sum();
1265 double w_owner = p(owner) / wsum;
1267 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1268 if (A == owner && A == k) {
1269 return Eigen::Vector3d::Zero();
1270 }
else if (A == owner) {
1271 return (point - atoms[k].getPos()) / rq(k);
1272 }
else if (A == k) {
1273 return -(point - atoms[k].
getPos()) / rq(k);
1275 return Eigen::Vector3d::Zero();
1278 Eigen::Vector3d rvec = atoms[a].
getPos() - atoms[b].
getPos();
1279 double Rab = rvec.norm();
1282 }
else if (A == b) {
1285 return Eigen::Vector3d::Zero();
1288 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
1289 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
1290 double Rab = 1.0 / Rij(a, b);
1291 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
1292 double mu = mu_table(a, b);
1293 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
1295 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
1296 constexpr double kNegligibleP = 1.e-8;
1297 if (p(k) < kNegligibleP) {
1298 return Eigen::Vector3d::Zero();
1300 Eigen::Vector3d total = Eigen::Vector3d::Zero();
1301 for (
Index b = k + 1; b < natoms; ++b) {
1302 if (hard(k, b) != 0) {
1305 double skv = sk_table(k, b);
1306 if (skv < kNegligibleP) {
1309 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
1311 for (
Index a = 0; a < k; ++a) {
1312 if (hard(a, k) != 0) {
1315 double skv = sk_table(a, k);
1316 double one_minus_skv = 1.0 - skv;
1317 if (one_minus_skv < kNegligibleP) {
1320 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
1323 return p(k) * total;
1326 constexpr double kNegligibleWOwner = 1.e-8;
1327 if (w_owner < kNegligibleWOwner) {
1330 double C_p = weight / w_owner;
1331 double prefactor = C_p * rho * xc.
f_xc;
1333 for (
Index A = 0; A < natoms; ++A) {
1334 Eigen::Vector3d dp_owner = dp_dR(owner, A);
1335 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
1336 for (
Index k = 0; k < natoms; ++k) {
1337 dwsum += dp_dR(k, A);
1339 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
1340 Eigen::Vector3d contribution = prefactor * dw;
1341 grad_thread[thread_id].row(A) += contribution.transpose();
1347 if (!eptr_weight_uks) {
1348 eptr_weight_uks = std::current_exception();
1353 if (eptr_weight_uks) {
1354 std::rethrow_exception(eptr_weight_uks);
1357 Eigen::MatrixXd grad = Eigen::MatrixXd::Zero(natoms, 3);
1358 for (
Index t = 0; t < nthreads; ++t) {
1359 grad += grad_thread[t];