393 auto const &system = get_system();
394 auto const &box_geo = *system.box_geo;
395 auto const dipole_prefac = prefactor /
Utils::product(dp3m.params.mesh);
398 if (dp3m.sum_mu2 > 0.) {
400 dp3m.fft_buffers->perform_vector_halo_gather();
401 for (
auto &rs_mesh : dp3m.fft_buffers->get_vector_mesh()) {
402 dp3m.fft->forward_fft(rs_mesh);
404 dp3m.update_mesh_views();
408 auto const wavevector = 2. * std::numbers::pi * box_geo.length_inv()[0];
409 auto const half_alpha_inv_sq =
Utils::sqr(1. / (2. * dp3m.params.alpha));
411 auto index = std::size_t(0u);
412 auto it_energy = dp3m.g_energy.begin();
413 for_each_3d(mesh_start, dp3m.mesh.size, local_index, [&]() {
414 auto constexpr KX = 2, KY = 0, KZ = 1;
415 auto const shift = local_index + dp3m.mesh.start;
416 auto const &d_op = dp3m.d_op[0u];
417 auto const &mesh_dip = dp3m.mesh.rs_fields;
418 auto const d_op_x = static_cast<FloatType>(d_op[shift[KX]]);
419 auto const d_op_y = static_cast<FloatType>(d_op[shift[KY]]);
420 auto const d_op_z = static_cast<FloatType>(d_op[shift[KZ]]);
423 auto const Mx_re = mesh_dip[0u][index];
424 auto const My_re = mesh_dip[1u][index];
425 auto const Mz_re = mesh_dip[2u][index];
426 auto const Q_re = Mx_re * d_op_x + My_re * d_op_y + Mz_re * d_op_z;
429 auto const Mx_im = mesh_dip[0u][index];
430 auto const My_im = mesh_dip[1u][index];
431 auto const Mz_im = mesh_dip[2u][index];
432 auto const Q_im = Mx_im * d_op_x + My_im * d_op_y + Mz_im * d_op_z;
435 auto const nx = static_cast<double>(d_op[shift[KX]]);
436 auto const ny = static_cast<double>(d_op[shift[KY]]);
437 auto const nz = static_cast<double>(d_op[shift[KZ]]);
438 auto const kx = nx * wavevector;
439 auto const ky = ny * wavevector;
440 auto const kz = nz * wavevector;
441 auto const norm_sq = Utils::sqr(kx) + Utils::sqr(ky) + Utils::sqr(kz);
443 auto const g = static_cast<double>(*it_energy);
444 auto const cell_energy =
445 g * static_cast<double>(Utils::sqr(Q_re) + Utils::sqr(Q_im));
446 auto const vterm = -2. * (1. / norm_sq + half_alpha_inv_sq);
449 auto const Rx = g * static_cast<double>(Mx_re * Q_re + Mx_im * Q_im);
450 auto const Ry = g * static_cast<double>(My_re * Q_re + My_im * Q_im);
451 auto const Rz = g * static_cast<double>(Mz_re * Q_re + Mz_im * Q_im);
462 node_k_space_pressure_tensor[0u] +=
463 cell_energy * (1. + vterm * kx * kx) + 2. * nx * Rx;
464 node_k_space_pressure_tensor[1u] +=
465 cell_energy * vterm * kx * ky + 2. * ny * Rx;
466 node_k_space_pressure_tensor[2u] +=
467 cell_energy * vterm * kx * kz + 2. * nz * Rx;
468 node_k_space_pressure_tensor[3u] +=
469 cell_energy * vterm * ky * kx + 2. * nx * Ry;
470 node_k_space_pressure_tensor[4u] +=
471 cell_energy * (1. + vterm * ky * ky) + 2. * ny * Ry;
472 node_k_space_pressure_tensor[5u] +=
473 cell_energy * vterm * ky * kz + 2. * nz * Ry;
474 node_k_space_pressure_tensor[6u] +=
475 cell_energy * vterm * kz * kx + 2. * nx * Rz;
476 node_k_space_pressure_tensor[7u] +=
477 cell_energy * vterm * kz * ky + 2. * ny * Rz;
478 node_k_space_pressure_tensor[8u] +=
479 cell_energy * (1. + vterm * kz * kz) + 2. * nz * Rz;
481 std::advance(it_energy, 1);
485 return node_k_space_pressure_tensor * dipole_prefac * std::numbers::pi *
486 box_geo.length_inv()[0];
491 bool force_flag,
bool energy_flag) {
494 auto const &system = get_system();
495 auto const &box_geo = *system.box_geo;
496 auto const dipole_prefac = prefactor /
Utils::product(dp3m.params.mesh);
500#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
501 auto constexpr r2c_dir = FFTConfig::r2c_dir;
502 auto const rs_local_size = dp3m.heffte.fft->rs_local_size();
503 auto const local_size = dp3m.heffte.fft->ks_local_size();
504 auto local_size_full = local_size;
505 if constexpr (FFTConfig::use_r2c) {
506 local_size_full[r2c_dir] -= 1;
507 local_size_full[r2c_dir] *= 2;
509 auto const local_origin = dp3m.heffte.fft->ks_local_ld_index();
511 auto const line_stride = local_size_full[0];
512 auto const plane_stride = local_size_full[0] * local_size_full[0];
514 auto const &global_size = dp3m.params.mesh;
515 auto const cutoff_left = 1 - local_origin[r2c_dir];
516 auto const cutoff_right = global_size[r2c_dir] / 2 - local_origin[r2c_dir];
517 auto &short_dim = local_index[r2c_dir];
518 dp3m.resize_heffte_buffers();
521 if (dp3m.sum_mu2 > 0.) {
523 dp3m.fft_buffers->perform_vector_halo_gather();
524 for (
auto &rs_mesh : dp3m.fft_buffers->get_vector_mesh()) {
525 dp3m.fft->forward_fft(rs_mesh);
527 dp3m.update_mesh_views();
529#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
530 if (dp3m.heffte.world_size == 1) {
532 std::array<FloatType *, 3u> rs_fields = {
533 {dp3m.heffte.rs_dipole_density[0u].data(),
534 dp3m.heffte.rs_dipole_density[1u].data(),
535 dp3m.heffte.rs_dipole_density[2u].data()}};
536 dp3m.heffte.halo_comm.gather_grid(
::comm_cart, rs_fields,
537 dp3m.local_mesh.dim);
539 for (
auto dir : {0u, 1u, 2u}) {
542 FFTConfig::r_space_order>(
543 dp3m.rs_field_no_halo_kokkos.data(),
544 dp3m.heffte.rs_dipole_density[dir], dp3m.local_mesh.dim,
545 dp3m.local_mesh.n_halo_ld,
546 dp3m.local_mesh.dim - dp3m.local_mesh.n_halo_ur);
548 std::size_t index_row_major = 0u;
549 for_each_3d_order<FFTConfig::k_space_order>(
550 mesh_start, rs_local_size, local_index, [&]() {
551 auto constexpr KX = 1, KY = 2, KZ = 0;
552 auto const index = local_index[KZ] +
553 rs_local_size[0] * local_index[KY] +
554 Utils::sqr(rs_local_size[0]) * local_index[KX];
555 dp3m.rs_field_no_halo_reorder_kokkos(index_row_major) =
556 dp3m.rs_field_no_halo_kokkos(index);
559 dp3m.heffte.fft->forward(dp3m.rs_field_no_halo_reorder_kokkos.data(),
560 dp3m.heffte.ks_dipole_density[dir].data());
562 if (not dp3m.params.tuning) {
563 std::size_t index_row_major_r2c = 0u;
564 for_each_3d_order<FFTConfig::k_space_order>(
565 mesh_start, local_size, local_index, [&]() {
566 if (not FFTConfig::use_r2c or (short_dim <= cutoff_right)) {
567 auto constexpr KX = 2, KY = 0, KZ = 1;
568 auto const index_fft_legacy = local_index[KZ] +
569 line_stride * local_index[KY] +
570 plane_stride * local_index[KX];
571 auto const old_value = std::complex<FloatType>{
572 dp3m.mesh.rs_fields[dir][2 * index_fft_legacy],
573 dp3m.mesh.rs_fields[dir][2 * index_fft_legacy + 1]};
574 auto const &new_value =
575 dp3m.heffte.ks_dipole_density[dir][index_row_major_r2c];
576 assert(heffte_almost_equal(new_value, old_value));
577 ++index_row_major_r2c;
592 if (dp3m.sum_mu2 > 0.) {
596 auto index = std::size_t(0u);
597 auto it_energy = dp3m.g_energy.begin();
598 auto node_energy = 0.;
599 for_each_3d(mesh_start, dp3m.mesh.size, local_index, [&]() {
600 auto constexpr KX = 2, KY = 0, KZ = 1;
601 auto const shift = local_index + dp3m.mesh.start;
602 auto const &d_op = dp3m.d_op[0u];
603 auto const &mesh_dip = dp3m.mesh.rs_fields;
605 auto const re = mesh_dip[0u][index] * FloatType(d_op[shift[KX]]) +
606 mesh_dip[1u][index] * FloatType(d_op[shift[KY]]) +
607 mesh_dip[2u][index] * FloatType(d_op[shift[KZ]]);
610 auto const im = mesh_dip[0u][index] * FloatType(d_op[shift[KX]]) +
611 mesh_dip[1u][index] * FloatType(d_op[shift[KY]]) +
612 mesh_dip[2u][index] * FloatType(d_op[shift[KZ]]);
614 node_energy += *it_energy * (Utils::sqr(re) + Utils::sqr(im));
615 std::advance(it_energy, 1);
617#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
618 if (dp3m.heffte.world_size == 1) {
619 [[maybe_unused]]
auto node_energy_heffte = 0.;
620 std::size_t index_row_major_r2c = 0u;
621 for_each_3d_order<FFTConfig::k_space_order>(
622 mesh_start, local_size, local_index, [&]() {
623 if (not FFTConfig::use_r2c or (short_dim <= cutoff_right)) {
624 auto const global_index = local_origin + local_index;
625 auto const &mesh_dip = dp3m.heffte.ks_dipole_density;
626 auto const cell_field =
627 mesh_dip[0u][index_row_major_r2c] *
628 FloatType(dp3m.d_op[0u][global_index[1u]]) +
629 mesh_dip[1u][index_row_major_r2c] *
630 FloatType(dp3m.d_op[1u][global_index[2u]]) +
631 mesh_dip[2u][index_row_major_r2c] *
632 FloatType(dp3m.d_op[2u][global_index[0u]]);
633 auto cell_energy =
static_cast<double>(
634 dp3m.heffte.g_energy[index_row_major_r2c] *
635 std::norm(cell_field));
636 if (FFTConfig::use_r2c and (short_dim >= cutoff_left and
637 short_dim <= cutoff_right - 1)) {
645 node_energy_heffte += cell_energy;
647 ++index_row_major_r2c;
649 assert(heffte_almost_equal(
static_cast<FloatType
>(node_energy_heffte),
650 static_cast<FloatType
>(node_energy)));
653 node_energy *= dipole_prefac * std::numbers::pi * box_geo.length_inv()[0];
654 boost::mpi::reduce(
comm_cart, node_energy, energy, std::plus<>(), 0);
656 if (dp3m.energy_correction == 0.)
657 calc_energy_correction();
661 energy -= prefactor * dp3m.sum_mu2 * std::numbers::inv_sqrtpi *
662 (2. / 3.) * Utils::int_pow<3>(dp3m.params.alpha);
665 energy += prefactor * dp3m.energy_correction / box_geo.volume();
675 if (dp3m.sum_mu2 > 0.) {
676 auto const wavenumber = 2. * std::numbers::pi * box_geo.length_inv()[0u];
677 dp3m.ks_scalar.resize(dp3m.local_mesh.size);
680 auto index{std::size_t(0u)};
681 auto it_energy = dp3m.g_energy.begin();
682 auto it_ks_scalar = dp3m.ks_scalar.begin();
683 for_each_3d(mesh_start, dp3m.mesh.size, local_index, [&]()
mutable {
684 auto constexpr KX = 2, KY = 0, KZ = 1;
685 auto const shift = local_index + dp3m.mesh.start;
686 auto const &d_op = dp3m.d_op[0u];
687 auto const &mesh_dip = dp3m.mesh.rs_fields;
689 auto const re = mesh_dip[0u][index] * FloatType(d_op[shift[KX]]) +
690 mesh_dip[1u][index] * FloatType(d_op[shift[KY]]) +
691 mesh_dip[2u][index] * FloatType(d_op[shift[KZ]]);
694 auto const im = mesh_dip[0u][index] * FloatType(d_op[shift[KX]]) +
695 mesh_dip[1u][index] * FloatType(d_op[shift[KY]]) +
696 mesh_dip[2u][index] * FloatType(d_op[shift[KZ]]);
698 *it_ks_scalar = *it_energy * std::complex<FloatType>{re, im};
699 std::advance(it_energy, 1);
700 std::advance(it_ks_scalar, 1);
703#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
704 if (dp3m.heffte.world_size == 1) {
705 std::size_t index_row_major_r2c = 0u;
706 for_each_3d_order<FFTConfig::k_space_order>(
707 mesh_start, local_size, local_index, [&]() {
708 if (not FFTConfig::use_r2c or (short_dim <= cutoff_right)) {
709 auto const global_index = local_origin + local_index;
710 auto const &mesh_dip = dp3m.heffte.ks_dipole_density;
711 dp3m.heffte.ks_scalar[index_row_major_r2c] =
712 dp3m.heffte.g_energy[index_row_major_r2c] *
713 (mesh_dip[0u][index_row_major_r2c] *
714 FloatType(dp3m.d_op[0u][global_index[1u]]) +
715 mesh_dip[1u][index_row_major_r2c] *
716 FloatType(dp3m.d_op[1u][global_index[2u]]) +
717 mesh_dip[2u][index_row_major_r2c] *
718 FloatType(dp3m.d_op[2u][global_index[0u]]));
720 if (not dp3m.params.tuning) {
721 auto constexpr KX = 2, KY = 0, KZ = 1;
722 auto const index_fft_legacy = local_index[KZ] +
723 line_stride * local_index[KY] +
724 plane_stride * local_index[KX];
725 assert(heffte_almost_equal(
726 dp3m.heffte.ks_scalar[index_row_major_r2c],
727 dp3m.ks_scalar[index_fft_legacy]));
730 ++index_row_major_r2c;
737 for (
int d = 0; d < 3; d++) {
738 auto it_ks_scalar = dp3m.ks_scalar.begin();
740 for_each_3d(mesh_start, dp3m.mesh.size, local_index, [&]() {
741 auto const &offset = dp3m.mesh.start;
742 auto const &d_op = dp3m.d_op[0u];
743 auto const d_op_val = FloatType(d_op[local_index[d] + offset[d]]);
744 auto const &value = *it_ks_scalar;
745 dp3m.mesh.rs_scalar[index] = d_op_val * value.real();
747 dp3m.mesh.rs_scalar[index] = d_op_val * value.imag();
749 std::advance(it_ks_scalar, 1);
751#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
752 if (dp3m.heffte.world_size == 1) {
753 unsigned int constexpr d_ks[3] = {2u, 0u, 1u};
754 std::size_t index_row_major_r2c = 0u;
755 for_each_3d_order<FFTConfig::k_space_order>(
756 mesh_start, local_size, local_index, [&]() {
757 if (not FFTConfig::use_r2c or (short_dim <= cutoff_right)) {
758 auto const global_index = local_origin + local_index;
759 auto const d_op_val =
760 FloatType(dp3m.d_op[d][global_index[d_ks[d]]]);
761 dp3m.heffte.ks_B_field_storage[index_row_major_r2c] =
762 d_op_val * dp3m.heffte.ks_scalar[index_row_major_r2c];
764 if (not dp3m.params.tuning) {
765 auto constexpr KX = 2, KY = 0, KZ = 1;
766 auto const index_fft_legacy =
767 local_index[KZ] + line_stride * local_index[KY] +
768 plane_stride * local_index[KX];
769 auto const old_value = std::complex<FloatType>{
770 dp3m.mesh.rs_scalar[2 * index_fft_legacy],
771 dp3m.mesh.rs_scalar[2 * index_fft_legacy + 1]};
772 auto const &new_value =
773 dp3m.heffte.ks_B_field_storage[index_row_major_r2c];
774 assert(heffte_almost_equal(new_value, old_value));
777 ++index_row_major_r2c;
780 dp3m.heffte.fft->backward(dp3m.heffte.ks_B_field_storage.data(),
781 dp3m.heffte.rs_B_fields_no_halo[d].data());
786 dp3m.heffte.rs_B_fields[d].data(),
787 std::span(dp3m.heffte.rs_B_fields_no_halo[d]),
788 dp3m.local_mesh.dim_no_halo, dp3m.local_mesh.n_halo_ld,
789 dp3m.local_mesh.n_halo_ur);
792 dp3m.heffte.rs_B_fields[d].data(),
793 dp3m.local_mesh.dim);
796 dp3m.fft->backward_fft(dp3m.fft_buffers->get_scalar_mesh());
798 dp3m.fft_buffers->perform_scalar_halo_spread();
800 auto const d_rs = (d + dp3m.mesh.ks_pnum) % 3;
801 Utils::integral_parameter<int, AssignTorques, p3m_min_cao, p3m_max_cao>(
802 dp3m.params.cao, dp3m, dipole_prefac * wavenumber, d_rs,
803 *system.cell_structure);
815 auto it_force = dp3m.g_force.begin();
816 auto it_ks_scalar = dp3m.ks_scalar.begin();
817 std::size_t index = 0u;
818 for_each_3d(mesh_start, dp3m.mesh.size, local_index, [&]() {
819 auto constexpr KX = 2, KY = 0, KZ = 1;
820 auto const shift = local_index + dp3m.mesh.start;
821 auto const &d_op = dp3m.d_op[0u];
822 auto const &mesh_dip = dp3m.mesh.rs_fields;
824 auto const re = mesh_dip[0u][index] * FloatType(d_op[shift[KX]]) +
825 mesh_dip[1u][index] * FloatType(d_op[shift[KY]]) +
826 mesh_dip[2u][index] * FloatType(d_op[shift[KZ]]);
829 auto const im = mesh_dip[0u][index] * FloatType(d_op[shift[KX]]) +
830 mesh_dip[1u][index] * FloatType(d_op[shift[KY]]) +
831 mesh_dip[2u][index] * FloatType(d_op[shift[KZ]]);
833 *it_ks_scalar = {*it_force * im, *it_force * (-re)};
834 std::advance(it_force, 1);
835 std::advance(it_ks_scalar, 1);
839#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
840 if (dp3m.heffte.world_size == 1) {
841 std::size_t index_row_major_r2c = 0u;
842 for_each_3d_order<FFTConfig::k_space_order>(
843 mesh_start, local_size, local_index, [&]() {
844 if (not FFTConfig::use_r2c or (short_dim <= cutoff_right)) {
845 auto const global_index = local_origin + local_index;
846 auto const &mesh_dip = dp3m.heffte.ks_dipole_density;
848 dp3m.heffte.g_force[index_row_major_r2c] *
849 (mesh_dip[0u][index_row_major_r2c] *
850 FloatType(dp3m.d_op[0u][global_index[1u]]) +
851 mesh_dip[1u][index_row_major_r2c] *
852 FloatType(dp3m.d_op[1u][global_index[2u]]) +
853 mesh_dip[2u][index_row_major_r2c] *
854 FloatType(dp3m.d_op[2u][global_index[0u]]));
855 dp3m.heffte.ks_scalar[index_row_major_r2c] = {value.imag(),
858 if (not dp3m.params.tuning) {
859 auto constexpr KX = 2, KY = 0, KZ = 1;
860 auto const index_fft_legacy = local_index[KZ] +
861 line_stride * local_index[KY] +
862 plane_stride * local_index[KX];
863 assert(heffte_almost_equal(
864 dp3m.heffte.ks_scalar[index_row_major_r2c],
865 dp3m.ks_scalar[index_fft_legacy]));
868 ++index_row_major_r2c;
875 for (
int d = 0; d < 3; d++) {
876 std::size_t index = 0u;
877 auto it_ks_scalar = dp3m.ks_scalar.begin();
878 for_each_3d(mesh_start, dp3m.mesh.size, local_index, [&]() {
879 auto constexpr KX = 2, KY = 0, KZ = 1;
880 auto const shift = local_index + dp3m.mesh.start;
881 auto const &d_op = dp3m.d_op[0u];
882 auto const &mesh_dip = dp3m.mesh.rs_fields;
883 auto const d_op_val = FloatType(d_op[shift[d]]);
884 auto const f = *it_ks_scalar * d_op_val;
885 mesh_dip[0u][index] = FloatType(d_op[shift[KX]]) * f.real();
886 mesh_dip[1u][index] = FloatType(d_op[shift[KY]]) * f.real();
887 mesh_dip[2u][index] = FloatType(d_op[shift[KZ]]) * f.real();
889 mesh_dip[0u][index] = FloatType(d_op[shift[KX]]) * f.imag();
890 mesh_dip[1u][index] = FloatType(d_op[shift[KY]]) * f.imag();
891 mesh_dip[2u][index] = FloatType(d_op[shift[KZ]]) * f.imag();
893 std::advance(it_ks_scalar, 1);
896#ifdef ESPRESSO_DP3M_HEFFTE_CROSS_CHECKS
897 if (dp3m.heffte.world_size == 1) {
898 std::size_t index_row_major_r2c = 0u;
899 for_each_3d_order<FFTConfig::k_space_order>(
900 mesh_start, local_size, local_index, [&]() {
901 if (not FFTConfig::use_r2c or (short_dim <= cutoff_right)) {
902 auto constexpr KX = 1, KY = 2, KZ = 0;
903 auto const global_index = local_origin + local_index;
904 auto const remapped_index =
905 local_index[KZ] + local_index[KY] * local_size[KZ] +
906 local_index[KX] * local_size[KZ] * local_size[KY];
907 auto const d_op_val =
908 FloatType(dp3m.d_op[d][global_index[d]]);
909 auto &mesh_dip = dp3m.heffte.ks_dipole_density;
910 mesh_dip[0u][index_row_major_r2c] =
911 FloatType(dp3m.d_op[d][global_index[2u]]) * d_op_val *
912 dp3m.heffte.ks_scalar[remapped_index];
913 mesh_dip[1u][index_row_major_r2c] =
914 FloatType(dp3m.d_op[d][global_index[0u]]) * d_op_val *
915 dp3m.heffte.ks_scalar[remapped_index];
916 mesh_dip[2u][index_row_major_r2c] =
917 FloatType(dp3m.d_op[d][global_index[1u]]) * d_op_val *
918 dp3m.heffte.ks_scalar[remapped_index];
920 if (not FFTConfig::use_r2c and not dp3m.params.tuning) {
921 auto const index_fft_legacy = local_index[2] +
922 line_stride * local_index[1] +
923 plane_stride * local_index[0];
924 for (
int j = 0; j < 3; ++j) {
925 auto const old_value = std::complex<FloatType>{
926 dp3m.mesh.rs_fields[j][2 * index_fft_legacy],
927 dp3m.mesh.rs_fields[j][2 * index_fft_legacy + 1]};
928 auto const &new_value = mesh_dip[j][index_row_major_r2c];
929 assert(heffte_almost_equal(new_value, old_value));
933 ++index_row_major_r2c;
936 for (
int dir = 0u; dir < 3u; ++dir) {
937 dp3m.heffte.fft->backward(
938 dp3m.heffte.ks_dipole_density[dir].data(),
939 dp3m.heffte.rs_B_fields_no_halo[dir].data());
944 dp3m.heffte.rs_B_fields[d].data(),
945 std::span(dp3m.heffte.rs_B_fields_no_halo[dir]),
946 dp3m.local_mesh.dim_no_halo, dp3m.local_mesh.n_halo_ld,
947 dp3m.local_mesh.n_halo_ur);
951 std::array<FloatType *, 3u>{{dp3m.heffte.rs_B_fields[0u].data(),
952 dp3m.heffte.rs_B_fields[1u].data(),
953 dp3m.heffte.rs_B_fields[2u].data()}};
954 dp3m.heffte.halo_comm.spread_grid(
::comm_cart, rs_fields,
955 dp3m.local_mesh.dim);
958 for (
auto &rs_mesh : dp3m.fft_buffers->get_vector_mesh()) {
959 dp3m.fft->backward_fft(rs_mesh);
962 dp3m.fft_buffers->perform_vector_halo_spread();
964 auto const d_rs = (d + dp3m.mesh.ks_pnum) % 3;
967 dp3m.params.cao, dp3m, dipole_prefac *
Utils::sqr(wavenumber), d_rs,
968 *system.cell_structure);
974 auto const surface_term = calc_surface_term(force_flag, energy_flag);
976 energy += surface_term;
980 if (force_flag and system.has_npt_enabled()) {
991 if (not energy_flag) {