81 const AOBasis& atom_basis,
const Eigen::MatrixXd& reference_density,
82 const Eigen::Vector3d& point) {
84 Eigen::VectorXd ao_values = Eigen::VectorXd::Zero(n);
85 Eigen::MatrixX3d ao_derivatives = Eigen::MatrixX3d::Zero(n, 3);
86 for (
const AOShell& shell : atom_basis) {
88 ao_values.segment(shell.getStartIndex(), shell.getNumFunc()) = vals.
values;
89 ao_derivatives.block(shell.getStartIndex(), 0, shell.getNumFunc(), 3) =
93 return 2.0 * ao_derivatives.transpose() * (reference_density * ao_values);
119 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
120 Index differentiate_atom_index,
const Eigen::Vector3d& point) {
121 double denominator = 0.0;
122 for (
Index j = 0; j < static_cast<Index>(atoms.size()); ++j) {
127 constexpr double kNegligibleDenominator = 1.e-12;
128 if (denominator < kNegligibleDenominator) {
129 return Eigen::Vector3d::Zero();
132 double w_target =
EvaluateWeight(atoms, target_atom_index, point);
134 atoms[differentiate_atom_index].basis,
135 atoms[differentiate_atom_index].density, point);
137 (differentiate_atom_index == target_atom_index) ? 1.0 : 0.0;
141 return (w_target - indicator) * grad_rho_A / denominator;
145 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
146 const Eigen::Vector3d& point) {
147 double denominator = 0.0;
148 Eigen::Vector3d grad_denominator = Eigen::Vector3d::Zero();
149 for (
Index j = 0; j < static_cast<Index>(atoms.size()); ++j) {
155 constexpr double kNegligibleDenominator = 1.e-12;
156 if (denominator < kNegligibleDenominator) {
157 return Eigen::Vector3d::Zero();
160 double w_target =
EvaluateWeight(atoms, target_atom_index, point);
162 atoms[target_atom_index].basis, atoms[target_atom_index].density, point);
165 return (grad_rho_target - w_target * grad_denominator) / denominator;
169 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
172 Eigen::MatrixXd W = Eigen::MatrixXd::Zero(full_size, full_size);
178 std::exception_ptr eptr_weightmatrix =
nullptr;
179#pragma omp parallel for schedule(guided)
186 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
189 Eigen::MatrixXd box_contribution =
192 for (
Index p = 0; p < static_cast<Index>(points.size()); ++p) {
200 (weights[p] * w_i) * (ao.
values * ao.
values.transpose());
210 if (!eptr_weightmatrix) {
211 eptr_weightmatrix = std::current_exception();
216 if (eptr_weightmatrix) {
217 std::rethrow_exception(eptr_weightmatrix);
221 W = 0.5 * (W + W.transpose());
253 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
254 const Eigen::MatrixXd& density_matrix,
const QMMolecule& mol,
260 std::vector<Eigen::MatrixXd> force_thread(nthreads,
261 Eigen::MatrixXd::Zero(natoms, 3));
263 std::exception_ptr eptr_gridweight =
nullptr;
264#pragma omp parallel for schedule(guided)
274 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
278 for (
Index pidx = 0; pidx < box.
size(); ++pidx) {
280 double rho_molecule = ao.
values.dot(DMAT_here * ao.
values);
281 double weight = weights[pidx];
282 if (std::abs(rho_molecule * weight) < 1.e-20) {
286 Index owner = owner_atoms[pidx];
288 throw std::runtime_error(
289 "GridWeightDerivativeContribution: grid point has no "
290 "owner_atom set -- was this grid built via GridSetup after "
291 "the owner-atom tracking change?");
294 const Eigen::Vector3d& point = points[pidx];
297 Eigen::VectorXd rq(natoms);
298 for (
Index k = 0; k < natoms; ++k) {
299 rq(k) = (point - mol[k].
getPos()).norm();
302 Eigen::VectorXd p = Eigen::VectorXd::Ones(natoms);
303 Eigen::MatrixXd mu_table = Eigen::MatrixXd::Zero(natoms, natoms);
304 Eigen::MatrixXd sk_table = Eigen::MatrixXd::Zero(natoms, natoms);
305 Eigen::MatrixXi hard = Eigen::MatrixXi::Zero(natoms, natoms);
306 for (
Index ii = 1; ii < natoms; ++ii) {
307 for (
Index jj = 0; jj < ii; ++jj) {
308 double mu = (rq(ii) - rq(jj)) * Rij(jj, ii);
309 mu_table(jj, ii) = mu;
310 if (mu > kSSWCutoff) {
313 }
else if (mu < -kSSWCutoff) {
317 double sk = SSWValue(mu);
318 sk_table(jj, ii) = sk;
324 double wsum = p.sum();
325 double w_owner = p(owner) / wsum;
326 constexpr double kNegligibleWOwner = 1.e-8;
327 if (w_owner < kNegligibleWOwner) {
330 double C_p = weight / w_owner;
332 auto d_rq_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
333 if (A == owner && A == k) {
334 return Eigen::Vector3d::Zero();
335 }
else if (A == owner) {
336 return (point - mol[k].getPos()) / rq(k);
338 return -(point - mol[k].
getPos()) / rq(k);
340 return Eigen::Vector3d::Zero();
343 Eigen::Vector3d rvec = mol[a].
getPos() - mol[b].
getPos();
344 double Rab = rvec.norm();
350 return Eigen::Vector3d::Zero();
353 Eigen::Vector3d d_rq_b = d_rq_dR(b, A);
354 Eigen::Vector3d d_rq_a = d_rq_dR(a, A);
355 double Rab = 1.0 / Rij(a, b);
356 Eigen::Vector3d dRab = d_Rab_dR(a, b, A);
357 double mu = mu_table(a, b);
358 return (d_rq_b - d_rq_a) / Rab - (mu / Rab) * dRab;
360 auto dp_dR = [&](
Index k,
Index A) -> Eigen::Vector3d {
361 constexpr double kNegligibleP = 1.e-8;
362 if (p(k) < kNegligibleP) {
363 return Eigen::Vector3d::Zero();
365 Eigen::Vector3d total = Eigen::Vector3d::Zero();
366 for (
Index b = k + 1; b < natoms; ++b) {
367 if (hard(k, b) != 0) {
370 double skv = sk_table(k, b);
371 if (skv < kNegligibleP) {
374 total += (SSWDerivative(mu_table(k, b)) / skv) * dmu_dR(k, b, A);
376 for (
Index a = 0; a < k; ++a) {
377 if (hard(a, k) != 0) {
380 double skv = sk_table(a, k);
381 double one_minus_skv = 1.0 - skv;
382 if (one_minus_skv < kNegligibleP) {
385 total += (-SSWDerivative(mu_table(a, k)) / one_minus_skv) *
394 double prefactor = C_p * w_c * rho_molecule;
396 for (
Index A = 0; A < natoms; ++A) {
397 Eigen::Vector3d dp_owner = dp_dR(owner, A);
398 Eigen::Vector3d dwsum = Eigen::Vector3d::Zero();
399 for (
Index k = 0; k < natoms; ++k) {
400 dwsum += dp_dR(k, A);
402 Eigen::Vector3d dw = dp_owner / wsum - w_owner * dwsum / wsum;
403 force_thread[thread_id].row(A) += (prefactor * dw).transpose();
409 if (!eptr_gridweight) {
410 eptr_gridweight = std::current_exception();
415 if (eptr_gridweight) {
416 std::rethrow_exception(eptr_gridweight);
419 Eigen::MatrixXd force_contribution = Eigen::MatrixXd::Zero(natoms, 3);
420 for (
Index t = 0; t < nthreads; ++t) {
421 force_contribution += force_thread[t];
423 return force_contribution;
427 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
428 const Eigen::MatrixXd& density_matrix,
const AOBasis& full_dftbasis,
433 std::vector<Eigen::MatrixXd> force_thread(nthreads,
434 Eigen::MatrixXd::Zero(natoms, 3));
436 std::exception_ptr eptr_pulaytranslation =
nullptr;
437#pragma omp parallel for schedule(guided)
447 const Eigen::MatrixXd DMAT_here =
452 std::vector<Index> local_idx_to_atom(box.
Matrixsize());
453 const std::vector<const AOShell*>& shells = box.
getShells();
454 const std::vector<GridboxRange>& ao_ranges = box.
getAOranges();
455 for (
size_t s = 0; s < shells.size(); ++s) {
456 Index atom = shells[s]->getAtomIndex();
457 for (
Index k = 0; k < ao_ranges[s].size; ++k) {
458 local_idx_to_atom[ao_ranges[s].start + k] = atom;
462 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
467 const Eigen::Vector3d& point = points[p];
469 Eigen::VectorXd temp = ao.
values.transpose() * DMAT_here;
470 double rho_molecule = 0.5 * temp.dot(ao.
values);
471 double weight = weights[p];
472 if (std::abs(rho_molecule * weight) < 1.e-20) {
483 Index atom = local_idx_to_atom[mu];
484 Eigen::Vector3d contribution =
485 -weight * w_c * temp(mu) * ao.
derivatives.row(mu).transpose();
486 force_thread[thread_id].row(atom) += contribution.transpose();
493 Index owner = owner_atoms[p];
495 throw std::runtime_error(
496 "PulayAndTranslationContribution: grid point has no "
497 "owner_atom set -- was this grid built via GridSetup after "
498 "the owner-atom tracking change?");
500 Eigen::Vector3d rho_molecule_grad = temp.transpose() * ao.
derivatives;
501 Eigen::Vector3d grad_w_c =
503 Eigen::Vector3d translation_term =
504 weight * (grad_w_c * rho_molecule + w_c * rho_molecule_grad);
505 force_thread[thread_id].row(owner) += translation_term.transpose();
510 if (!eptr_pulaytranslation) {
511 eptr_pulaytranslation = std::current_exception();
516 if (eptr_pulaytranslation) {
517 std::rethrow_exception(eptr_pulaytranslation);
520 Eigen::MatrixXd force_contribution = Eigen::MatrixXd::Zero(natoms, 3);
521 for (
Index t = 0; t < nthreads; ++t) {
522 force_contribution += force_thread[t];
524 return force_contribution;
528 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
529 const Eigen::MatrixXd& density_matrix,
const AOBasis& full_dftbasis,
534 std::vector<Eigen::MatrixXd> force_thread(nthreads,
535 Eigen::MatrixXd::Zero(natoms, 3));
537 std::exception_ptr eptr_weightfunction =
nullptr;
538#pragma omp parallel for schedule(guided)
547 const std::vector<Eigen::Vector3d>& points = box.
getGridPoints();
551 const Eigen::Vector3d& point = points[p];
553 double rho_molecule = ao.
values.dot(DMAT_here * ao.
values);
554 double weight = weights[p];
555 if (std::abs(rho_molecule * weight) < 1.e-20) {
558 double prefactor = weight * rho_molecule;
559 for (
Index A = 0; A < natoms; ++A) {
560 Eigen::Vector3d dw_dR_A =
562 force_thread[thread_id].row(A) += (prefactor * dw_dR_A).transpose();
568 if (!eptr_weightfunction) {
569 eptr_weightfunction = std::current_exception();
574 if (eptr_weightfunction) {
575 std::rethrow_exception(eptr_weightfunction);
578 Eigen::MatrixXd force_contribution = Eigen::MatrixXd::Zero(natoms, 3);
579 for (
Index t = 0; t < nthreads; ++t) {
580 force_contribution += force_thread[t];
582 return force_contribution;
586 const std::vector<AtomicReference>& atoms,
Index target_atom_index,
587 const Eigen::MatrixXd& density_matrix,
const QMMolecule& mol,
591 density_matrix, mol, grid) +
593 atoms, target_atom_index, density_matrix, full_dftbasis, grid) +
595 density_matrix, full_dftbasis, grid);