88 const AOBasis& atom_basis,
const Eigen::MatrixXd& reference_density,
89 const Eigen::Vector3d& point) {
91 Eigen::VectorXd ao_values = Eigen::VectorXd::Zero(n);
92 Eigen::MatrixX3d ao_derivatives = Eigen::MatrixX3d::Zero(n, 3);
93 for (
const AOShell& shell : atom_basis) {
95 ao_values.segment(shell.getStartIndex(), shell.getNumFunc()) = vals.
values;
96 ao_derivatives.block(shell.getStartIndex(), 0, shell.getNumFunc(), 3) =
103 return 2.0 * ao_derivatives.transpose() * (reference_density * ao_values);
132 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
133 Index differentiate_atom_index,
const Eigen::Vector3d& point) {
134 double denominator = 0.0;
135 for (
Index j = 0; j < static_cast<Index>(atoms.size()); ++j) {
142 constexpr double kNegligibleDenominator = 1.e-12;
143 if (denominator < kNegligibleDenominator) {
144 return Eigen::Vector3d::Zero();
147 double w_target =
EvaluateWeight(atoms, target_atom_index, point);
149 atoms[differentiate_atom_index].basis,
150 atoms[differentiate_atom_index].density, point);
152 (differentiate_atom_index == target_atom_index) ? 1.0 : 0.0;
156 return (w_target - indicator) * grad_rho_A / denominator;
160 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
161 const Eigen::Vector3d& point) {
162 double denominator = 0.0;
163 Eigen::Vector3d grad_denominator = Eigen::Vector3d::Zero();
164 for (
Index j = 0; j < static_cast<Index>(atoms.size()); ++j) {
170 constexpr double kNegligibleDenominator = 1.e-12;
171 if (denominator < kNegligibleDenominator) {
172 return Eigen::Vector3d::Zero();
175 double w_target =
EvaluateWeight(atoms, target_atom_index, point);
177 atoms[target_atom_index].basis, atoms[target_atom_index].density, point);
180 return (grad_rho_target - w_target * grad_denominator) / denominator;
184 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
187 Eigen::MatrixXd W = Eigen::MatrixXd::Zero(full_size, full_size);
199 std::exception_ptr eptr_weightmatrix =
nullptr;
200#pragma omp parallel for schedule(guided)
207 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
210 Eigen::MatrixXd box_contribution =
213 for (
Index p = 0; p < static_cast<Index>(points.size()); ++p) {
223 (weights[p] * w_i) * (ao.
values * ao.
values.transpose());
233 if (!eptr_weightmatrix) {
234 eptr_weightmatrix = std::current_exception();
239 if (eptr_weightmatrix) {
240 std::rethrow_exception(eptr_weightmatrix);
248 W = 0.5 * (W + W.transpose());
285 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
286 const Eigen::MatrixXd& density_matrix,
const QMMolecule& mol,
292 std::vector<Eigen::MatrixXd> force_thread(nthreads,
293 Eigen::MatrixXd::Zero(natoms, 3));
295 std::exception_ptr eptr_gridweight =
nullptr;
296#pragma omp parallel for schedule(guided)
306 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
310 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
312 double rho_molecule = ao.
values.dot(DMAT_here * ao.
values);
313 double weight = weights[pidx];
314 if (std::abs(rho_molecule * weight) < 1.e-20) {
318 Index owner = owner_atoms[pidx];
320 throw std::runtime_error(
321 "GridWeightDerivativeContribution: grid point has no "
322 "owner_atom set -- was this grid built via GridSetup after "
323 "the owner-atom tracking change?");
326 const Eigen::Vector3d& point = points[pidx];
329 Eigen::VectorXd rq(natoms);
330 for (
Index k = 0; k < natoms; ++k) {
331 rq(k) = (point - mol[k].
getPos()).norm();
334 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
335 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
336 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
337 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
338 for (
Index ii = 1; ii < natoms; ++ii) {
339 for (
Index jj = 0; jj < ii; ++jj) {
340 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
341 mu_table(jj, ii) = mu;
342 if (mu > kSSWCutoff) {
345 }
else if (mu < -kSSWCutoff) {
349 double sk = SSWValue(mu);
350 sk_table(jj, ii) = sk;
356 double wsum = p.sum();
357 double w_owner = p(owner) / wsum;
358 constexpr double kNegligibleWOwner = 1.e-8;
359 if (w_owner < kNegligibleWOwner) {
362 double C_p = weight / w_owner;
364 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
365 if (A == owner && A == k) {
366 return Eigen::Vector3d::Zero();
367 }
else if (A == owner) {
368 return (point - mol[k].getPos()) / rq(k);
370 return -(point - mol[k].
getPos()) / rq(k);
372 return Eigen::Vector3d::Zero();
375 Eigen::Vector3d rvec = mol[a].
getPos() - mol[b].
getPos();
376 double Rab = rvec.norm();
382 return Eigen::Vector3d::Zero();
385 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
386 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
387 double Rab = 1.0 / Rij(a, b);
388 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
389 double mu = mu_table(a, b);
390 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
392 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
393 constexpr double kNegligibleP = 1.e-8;
394 if (p(k) < kNegligibleP) {
395 return Eigen::Vector3d::Zero();
397 Eigen::Vector3d total = Eigen::Vector3d::Zero();
398 for (
Index b = k + 1; b < natoms; ++b) {
399 if (hard(k, b) != 0) {
402 double skv = sk_table(k, b);
403 if (skv < kNegligibleP) {
406 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
408 for (
Index a = 0; a < k; ++a) {
409 if (hard(a, k) != 0) {
412 double skv = sk_table(a, k);
413 double one_minus_skv = 1.0 - skv;
414 if (one_minus_skv < kNegligibleP) {
417 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
430 double prefactor = C_p * w_c * rho_molecule;
432 for (
Index A = 0; A < natoms; ++A) {
433 Eigen::Vector3d dp_owner = dp_dR(owner, A);
434 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
435 for (
Index k = 0; k < natoms; ++k) {
436 dwsum += dp_dR(k, A);
438 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
439 force_thread[thread_id].row(A) += (prefactor * dw).transpose();
445 if (!eptr_gridweight) {
446 eptr_gridweight = std::current_exception();
451 if (eptr_gridweight) {
452 std::rethrow_exception(eptr_gridweight);
455 Eigen::MatrixXd force_contribution = Eigen::MatrixXd::Zero(natoms, 3);
456 for (
Index t = 0; t < nthreads; ++t) {
457 force_contribution += force_thread[t];
459 return force_contribution;
463 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
464 const Eigen::MatrixXd& density_matrix,
const AOBasis& full_dftbasis,
469 std::vector<Eigen::MatrixXd> force_thread(nthreads,
470 Eigen::MatrixXd::Zero(natoms, 3));
472 std::exception_ptr eptr_pulaytranslation =
nullptr;
473#pragma omp parallel for schedule(guided)
487 const Eigen::MatrixXd DMAT_here =
493 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
494 const std::vector<const AOShell*>& shells = box.
getShells();
495 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
496 for (
size_t s = 0; s < shells.size(); ++s) {
497 Index atom = shells[s]->getAtomIndex();
498 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
499 local_idx_to_atom[ao_ranges[s].start + k] = atom;
503 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
508 const Eigen::Vector3d& point = points[p];
510 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
511 double rho_molecule = 0.5 * temp.dot(ao.
values);
512 double weight = weights[p];
513 if (std::abs(rho_molecule * weight) < 1.e-20) {
525 Index atom = local_idx_to_atom[mu];
526 Eigen::Vector3d contribution =
527 -weight * w_c * temp(mu) * ao.
derivatives.row(mu).transpose();
528 force_thread[thread_id].row(atom) += contribution.transpose();
539 Index owner = owner_atoms[p];
541 throw std::runtime_error(
542 "PulayAndTranslationContribution: grid point has no "
543 "owner_atom set -- was this grid built via GridSetup after "
544 "the owner-atom tracking change?");
546 Eigen::Vector3d rho_molecule_grad = temp.transpose() * ao.
derivatives;
547 Eigen::Vector3d grad_w_c =
549 Eigen::Vector3d translation_term =
550 weight * (grad_w_c * rho_molecule + w_c * rho_molecule_grad);
551 force_thread[thread_id].row(owner) += translation_term.transpose();
556 if (!eptr_pulaytranslation) {
557 eptr_pulaytranslation = std::current_exception();
562 if (eptr_pulaytranslation) {
563 std::rethrow_exception(eptr_pulaytranslation);
566 Eigen::MatrixXd force_contribution = Eigen::MatrixXd::Zero(natoms, 3);
567 for (
Index t = 0; t < nthreads; ++t) {
568 force_contribution += force_thread[t];
570 return force_contribution;
574 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
575 const Eigen::MatrixXd& density_matrix,
const AOBasis& full_dftbasis,
580 std::vector<Eigen::MatrixXd> force_thread(nthreads,
581 Eigen::MatrixXd::Zero(natoms, 3));
583 std::exception_ptr eptr_weightfunction =
nullptr;
584#pragma omp parallel for schedule(guided)
593 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
597 const Eigen::Vector3d& point = points[p];
599 double rho_molecule = ao.
values.dot(DMAT_here * ao.
values);
600 double weight = weights[p];
601 if (std::abs(rho_molecule * weight) < 1.e-20) {
604 double prefactor = weight * rho_molecule;
605 for (
Index A = 0; A < natoms; ++A) {
606 Eigen::Vector3d dw_dR_A =
608 force_thread[thread_id].row(A) += (prefactor * dw_dR_A).transpose();
614 if (!eptr_weightfunction) {
615 eptr_weightfunction = std::current_exception();
620 if (eptr_weightfunction) {
621 std::rethrow_exception(eptr_weightfunction);
624 Eigen::MatrixXd force_contribution = Eigen::MatrixXd::Zero(natoms, 3);
625 for (
Index t = 0; t < nthreads; ++t) {
626 force_contribution += force_thread[t];
628 return force_contribution;
632 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
633 const Eigen::MatrixXd& density_matrix,
const QMMolecule& mol,
639 density_matrix, mol, grid) +
641 atoms, target_atom_index, density_matrix, full_dftbasis, grid) +
643 density_matrix, full_dftbasis, grid);