156 log::info(
" PAW: one-center engine active for {} atoms",
158 build_occupation_symmetrizer();
161 restore_one_center_occupations();
181 update_one_center_scf_correction();
184 auto timer_one_center_start = std::chrono::high_resolution_clock::now();
185 refresh_one_center_terms();
186 update_one_center_scf_correction();
187 auto timer_one_center_end = std::chrono::high_resolution_clock::now();
189 " PAW one-center refresh: {:.1f} ms",
190 std::chrono::duration<double, std::milli>(timer_one_center_end - timer_one_center_start)
220 symmetrize_projector_overlaps();
288 auto& current = current_matrix.
raw();
289 auto& previous = previous_matrix.
raw();
290 if (previous.size() != current.size()) {
291 previous_matrix = current_matrix;
292 return std::numeric_limits<Real>::max();
295 for (
size_t index = 0; index < current.size(); index++) {
296 Real step = current[index] - previous[index];
297 residual += step * step;
300 previous_matrix = current_matrix;
311 add_one_center_to_d_matrix();
375 log::info(
" -> PAW hartree energy AE = {:14.9f}", branches.all_electron_hartree);
376 log::info(
" -> PAW hartree energy PS = {:14.9f}", branches.pseudo_hartree);
377 log::info(
" -> PAW xc energy AE = {:14.9f}", branches.all_electron_xc);
378 log::info(
" -> PAW xc energy PS = {:14.9f}", branches.pseudo_xc);
390 void restore_one_center_occupations() {
393 throw std::runtime_error(
394 "PAW: the checkpoint's on-site occupations have " +
395 std::to_string(preloaded.size()) +
" spin channel(s), but this run has " +
397 ". A non-self-consistent run must use the spin treatment of the SCF that wrote "
399 for (
size_t spin = 0; spin < preloaded.size(); spin++) {
401 if (preloaded[spin].rows() != expected.rows() ||
402 preloaded[spin].cols() != expected.cols())
403 throw std::runtime_error(
404 "PAW: the checkpoint's on-site occupations are " +
405 std::to_string(preloaded[spin].rows()) +
" by " +
406 std::to_string(preloaded[spin].cols()) +
", but this run's are " +
407 std::to_string(expected.rows()) +
" by " + std::to_string(expected.cols()) +
408 ". A non-self-consistent run must use the structure and datasets of the "
409 "SCF that wrote the checkpoint.");
413 std::fill(total.begin(), total.end(), 0.0);
414 for (
const auto& per_spin : preloaded) {
415 const auto& values = per_spin.raw();
416 for (
size_t index = 0; index < total.size(); index++)
417 total[index] += values[index];
419 refresh_one_center_terms();
420 log::info(
" PAW: one-center terms built from the checkpoint's on-site occupations");
441 void build_occupation_symmetrizer() {
445 std::vector<paw_one_center::ChannelAngularLayout> layout_by_species;
446 layout_by_species.reserve(
static_cast<size_t>(
crystal_structure().number_of_species()));
449 int channels = basis.number_of_projector_channels(species_index);
450 std::vector<int> beta_index(
static_cast<size_t>(channels));
451 std::vector<int> angular_momentum(
static_cast<size_t>(channels));
452 for (
int channel = 0; channel < channels; channel++) {
453 beta_index[
static_cast<size_t>(channel)] =
454 basis.projector_to_beta_index(species_index, channel);
455 angular_momentum[
static_cast<size_t>(channel)] =
456 basis.projector_angular_momentum(species_index, channel);
458 layout_by_species.push_back(
464 log::info(
" PAW: on-site occupations symmetrized over {} symmetry operations",
492 void symmetrize_projector_overlaps() {
501 void refresh_one_center_terms() {
504 std::vector<const Matrix<Real>*> coefficient_pointers_by_spin;
507 coefficient_pointers_by_spin.push_back(&per_spin);
509 crystal_structure(), coefficient_pointers_by_spin, projector_overlap_row_capacity());
512 void add_one_center_to_d_matrix() {
522 std::vector<std::vector<Real>> corrections(number_of_atoms);
523 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++)
536 void update_one_center_scf_correction() {
542 [[nodiscard]]
Real contract_with_one_center_potential(
543 const std::vector<Matrix<Real>>& coefficients_by_spin)
const {
546 Real accumulated = 0.0;
555 for (
size_t spin = 0; spin < coefficients_by_spin.size(); spin++) {
556 const auto& coefficients_for_spin = coefficients_by_spin[spin];
559 const auto& correction =
561 if (correction.empty())
565 for (
int first = 0; first < number_of_channels; first++) {
566 for (
int second = 0; second < number_of_channels; second++) {
568 coefficients_for_spin[atom_index][first * number_of_channels + second] *
569 correction[first * number_of_channels + second];
585 [[nodiscard]]
int projector_overlap_row_capacity()
const {
586 int maximum_channels = 0;
591 std::max(maximum_channels, basis.number_of_projector_channels(species_index));
592 return maximum_channels;