24#if defined(ESPRESSO_P3M) || defined(ESPRESSO_DP3M)
35#include "communication.hpp"
36#include "system/System.hpp"
66 auto const min_box_l = std::ranges::min(box_geo.length());
67 auto const min_local_box_l = std::ranges::min(local_geo.length());
69 m_r_cut_iL_max = std::min(min_local_box_l, min_box_l / 2.) - verlet_skin;
74 m_logger->report_fixed_r_cut_iL(r_cut_iL);
92 double r_cut_iL,
double alpha_L) {
95 p3m_params.r_cut = r_cut_iL * box_geo.length()[0];
96 p3m_params.r_cut_iL = r_cut_iL;
98 p3m_params.alpha_L = alpha_L;
99 p3m_params.alpha = alpha_L * box_geo.length_inv()[0];
100 p3m_params.mesh = mesh;
120 double &tuned_r_cut_iL,
121 double &tuned_alpha_L,
122 double &tuned_accuracy) {
127 double rs_err, ks_err;
132 auto const k_cut_per_dir = (
static_cast<double>(cao) / 2.) *
134 auto const k_cut = std::ranges::min(k_cut_per_dir);
135 auto const min_box_l = std::ranges::min(box_geo.length());
136 auto const min_local_box_l = std::ranges::min(local_geo.length());
137 auto const k_cut_max = std::min(min_box_l, min_local_box_l) - verlet_skin;
139 if (cao >= std::ranges::min(mesh) or k_cut >= k_cut_max) {
140 m_logger->log_cao_too_large(mesh[0], cao);
144 std::tie(tuned_accuracy, rs_err, ks_err, tuned_alpha_L) =
151 if (tuned_accuracy > target_accuracy) {
152 m_logger->log_skip(
"accuracy not achieved", mesh[0], cao, r_cut_iL_max,
153 tuned_alpha_L, tuned_accuracy, rs_err, ks_err);
157 double r_cut_iL, accuracy;
159 r_cut_iL = 0.5 * (r_cut_iL_min + r_cut_iL_max);
165 std::tie(accuracy, rs_err, ks_err, tuned_alpha_L) =
167 if (accuracy > target_accuracy)
168 r_cut_iL_min = r_cut_iL;
170 r_cut_iL_max = r_cut_iL;
175 tuned_r_cut_iL = r_cut_iL = r_cut_iL_max;
177 auto const report_veto = [&](
auto const &veto) {
179 m_logger->log_skip(*veto, mesh[0], cao, r_cut_iL, tuned_alpha_L,
180 tuned_accuracy, rs_err, ks_err);
182 return static_cast<bool>(veto);
186 auto const r_cut = r_cut_iL * box_geo.length()[0];
191 commit(mesh, cao, r_cut_iL, tuned_alpha_L);
198 std::tie(tuned_accuracy, rs_err, ks_err, tuned_alpha_L) =
201 m_logger->log_success(int_time, mesh[0], cao, r_cut_iL, tuned_alpha_L,
202 tuned_accuracy, rs_err, ks_err);
225 double &tuned_r_cut_iL,
226 double &tuned_alpha_L,
227 double &tuned_accuracy) {
228 double best_time = -1., tmp_r_cut_iL = 0., tmp_alpha_L = 0.,
240 tmp_time =
get_mc_time(mesh, cao, tmp_r_cut_iL, tmp_alpha_L, tmp_accuracy);
247 if (tmp_time >= 0.) {
248 best_time = tmp_time;
249 tuned_r_cut_iL = tmp_r_cut_iL;
250 tuned_alpha_L = tmp_alpha_L;
251 tuned_accuracy = tmp_accuracy;
271 if (final_dir == 0) {
274 for (final_dir = -1; final_dir <= 1; final_dir += 2) {
276 mesh, cao + final_dir, tmp_r_cut_iL, tmp_alpha_L, tmp_accuracy);
282 if (tmp_time < best_time) {
283 best_time = tmp_time;
284 tuned_r_cut_iL = tmp_r_cut_iL;
285 tuned_alpha_L = tmp_alpha_L;
286 tuned_accuracy = tmp_accuracy;
287 tuned_cao = cao + final_dir;
291 if (dir_times[0] == best_time) {
293 }
else if (dir_times[2] == best_time) {
300 (dir_times[2] < 0 || dir_times[2] > dir_times[0]))
303 else if ((dir_times[2] >= 0 &&
305 (dir_times[0] < 0 || dir_times[0] > dir_times[2]))
313 cao += 2 * final_dir;
322 tmp_time =
get_mc_time(mesh, cao, tmp_r_cut_iL, tmp_alpha_L, tmp_accuracy);
327 if (tmp_time < best_time) {
328 best_time = tmp_time;
329 tuned_r_cut_iL = tmp_r_cut_iL;
330 tuned_alpha_L = tmp_alpha_L;
331 tuned_accuracy = tmp_accuracy;
static auto constexpr P3M_TUNE_ACCURACY_TOO_LARGE
could not achieve target accuracy
static auto constexpr P3M_RCUT_PREC
Precision threshold for a non-zero real-space cutoff.
static auto constexpr P3M_TUNE_ELC_GAP_SIZE
conflict with ELC gap size
static auto constexpr P3M_TUNE_FFT_MESH_SIZE
conflict with FFT domain decomposition
static auto constexpr P3M_TUNE_CAO_TOO_LARGE
charge assignment order too large for mesh size
std::shared_ptr< LocalBox > local_geo
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
double get_m_time(Utils::Vector3i const &mesh, int &tuned_cao, double &tuned_r_cut_iL, double &tuned_alpha_L, double &tuned_accuracy)
Get the optimal alpha and the corresponding computation time for a fixed mesh.
virtual std::optional< std::string > fft_decomposition_veto(Utils::Vector3i const &) const
Veto FFT decomposition in non-cubic boxes.
System::System & m_system
virtual void on_solver_change() const =0
Re-initialize the currently active solver.
double get_mc_time(Utils::Vector3i const &mesh, int cao, double &tuned_r_cut_iL, double &tuned_alpha_L, double &tuned_accuracy)
Get the optimal alpha and the corresponding computation time for a fixed mesh and cao.
virtual std::tuple< double, double, double, double > calculate_accuracy(Utils::Vector3i const &mesh, int cao, double r_cut_iL) const =0
Get the minimal error for this combination of parameters.
void increment_n_trials()
virtual std::optional< std::string > layer_correction_veto_r_cut(double r_cut) const =0
Veto real-space cutoffs larger than the layer correction gap.
void commit(Utils::Vector3i const &mesh, int cao, double r_cut_iL, double alpha_L)
Write tuned parameters to the P3M parameter struct.
void determine_cao_limits(int initial_cao)
Determine a sensible range for the charge assignment order.
void determine_r_cut_limits()
Determine a sensible range for the real-space cutoff.
virtual P3MParameters & get_params()=0
Get the P3M parameters.
std::unique_ptr< TuningLogger > m_logger
static auto constexpr time_granularity
Granularity of the time measurement (milliseconds).
constexpr int p3m_min_cao
Minimal charge assignment order.
constexpr int p3m_max_cao
Maximal charge assignment order.
auto hadamard_division(Vector< T, N > const &a, Vector< U, N > const &b)
Common functions for dipolar and charge P3M.
double r_cut_iL
cutoff radius for real space electrostatics (>0), rescaled to r_cut_iL = r_cut * box_l_i.
int cao
charge assignment order ([0,7]).
double accuracy
accuracy of the actual parameter set.
double benchmark_integration_step(System::System &system, int int_steps)
Benchmark the integration loop.