ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
dp3m.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2024 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/** @file
23 * P3M algorithm for long-range magnetic dipole-dipole interaction.
24 *
25 * We use here a P3M (Particle-Particle Particle-Mesh) method based
26 * on the dipolar Ewald summation. Details of the used method can be
27 * found in @cite hockney88a and @cite deserno98a @cite deserno98b.
28 *
29 * Further reading: @cite cerda08d
30 */
31
32#pragma once
33
34#include <config/config.hpp>
35
36#ifdef ESPRESSO_DP3M
37
39
40#include "p3m/common.hpp"
41#include "p3m/data_struct.hpp"
42#include "p3m/math.hpp"
43
44#include "Particle.hpp"
45#include "ParticleRange.hpp"
46
47#include <utils/Vector.hpp>
49#include <utils/math/sqr.hpp>
50
51#include <cmath>
52#include <numbers>
53
54/** @brief Dipolar P3M solver. */
55struct DipolarP3M : public Dipoles::Actor<DipolarP3M> {
57
58public:
60
61 virtual ~DipolarP3M() = default;
62
63 [[nodiscard]] virtual bool is_tuned() const noexcept = 0;
64 [[nodiscard]] virtual bool is_gpu() const noexcept = 0;
65 [[nodiscard]] virtual bool is_double_precision() const noexcept = 0;
66
67 virtual void on_activation() = 0;
68 /** @brief Recalculate all box-length-dependent parameters. */
76 /** @brief Recalculate all derived parameters. */
77 virtual void init() = 0;
78
85
86 /**
87 * @brief Count the number of magnetic particles and calculate
88 * the sum of the squared dipole moments.
89 */
90 virtual void count_magnetic_particles() = 0;
91
92 /** Assign the physical dipoles using the tabulated assignment function. */
93 virtual void dipole_assign(ParticleRange const &particles) = 0;
94
95 /**
96 * @brief Tune dipolar P3M parameters to desired accuracy.
97 *
98 * The parameters
99 * @ref P3MParameters::mesh "mesh",
100 * @ref P3MParameters::cao "cao",
101 * @ref P3MParameters::r_cut_iL "r_cut_iL" and
102 * @ref P3MParameters::alpha_L "alpha_L" are tuned to obtain the target
103 * @ref P3MParameters::accuracy "accuracy" in optimal time.
104 * These parameters are stored in the @ref dp3m_params object.
105 *
106 * The function utilizes the analytic expression of the error estimate
107 * for the dipolar P3M method in the paper of @cite cerda08d in
108 * order to obtain the rms error in the force for a system of N randomly
109 * distributed particles in a cubic box. For the real space error, the
110 * estimate in @cite kolafa92a is used.
111 *
112 * Parameter ranges if not given explicitly in the constructor:
113 * - @p mesh is set up such that the number of mesh points is equal to the
114 * number of magnetic dipolar particles
115 * - @p cao explores all possible values
116 * - @p alpha_L is tuned for each tuple (@p r_cut_iL, @p mesh, @p cao) and
117 * calculated assuming that the error contributions of real and reciprocal
118 * space should be equal
119 *
120 * After checking if the total error lies below the target accuracy,
121 * the time needed for one force calculation is measured. Parameters
122 * that minimize the runtime are kept.
123 *
124 * The function is based on routines of the program HE_Q.cpp for charges
125 * written by M. Deserno.
126 */
127 virtual void tune() = 0;
128
129 /** Compute the k-space part of energies. */
130 virtual double long_range_energy(ParticleRange const &particles) = 0;
131
132 /** Compute the k-space part of forces. */
133 virtual void add_long_range_forces(ParticleRange const &particles) = 0;
134
135 /** Calculate real-space contribution of p3m dipolar pair forces and torques.
136 * If NPT is compiled in, update the NpT virial.
137 */
138 inline ParticleForce pair_force(double d1d2, Utils::Vector3d const &dip1,
139 Utils::Vector3d const &dip2,
140 Utils::Vector3d const &d, double dist,
141 double dist2) const {
142 if (d1d2 == 0. or dist >= dp3m_params.r_cut or dist <= 0.)
143 return {};
144
145 auto const alpsq = dp3m_params.alpha * dp3m_params.alpha;
146 auto const adist = dp3m_params.alpha * dist;
147#if USE_ERFC_APPROXIMATION
148 auto const erfc_part_ri = Utils::AS_erfc_part(adist) / dist;
149#else
150 auto const erfc_part_ri = erfc(adist) / dist;
151#endif
152
153 // Calculate scalar multiplications for vectors mi, mj, rij
154 auto const mimj = dip1 * dip2;
155
156 auto const mir = dip1 * d;
157 auto const mjr = dip2 * d;
158
159 auto const coeff = 2. * dp3m_params.alpha * std::numbers::inv_sqrtpi;
160 auto const dist2i = 1. / dist2;
161 auto const exp_adist2 = exp(-Utils::sqr(adist));
162
163 auto const B_r = (dp3m_params.accuracy > 5e-06)
164 ? (erfc_part_ri + coeff) * exp_adist2 * dist2i
165 : (erfc(adist) / dist + coeff * exp_adist2) * dist2i;
166
167 auto const common_term = alpsq * coeff * exp_adist2;
168 auto const C_r = dist2i * (3. * B_r + 2. * common_term);
169 auto const D_r = dist2i * (5. * C_r + 4. * common_term * alpsq);
170
171 // Calculate real-space forces
172 auto const force = prefactor * ((mimj * d + dip1 * mjr + dip2 * mir) * C_r -
173 mir * mjr * D_r * d);
174
175 // Calculate vector multiplications for vectors mi, mj, rij
176 auto const mixmj = vector_product(dip1, dip2);
177 auto const mixr = vector_product(dip1, d);
178
179 // Calculate real-space torques
180 auto const torque = prefactor * (-mixmj * B_r + mixr * (mjr * C_r));
181#ifdef ESPRESSO_NPT
182#if USE_ERFC_APPROXIMATION
183 auto const fac = prefactor * d1d2 * exp_adist2;
184#else
185 auto const fac = prefactor * d1d2;
186#endif
187 auto const energy = fac * (mimj * B_r - mir * mjr * C_r);
189#endif // ESPRESSO_NPT
190 return ParticleForce{force, torque};
191 }
192
193 /** Calculate real-space contribution of dipolar pair energy. */
194 inline double pair_energy(Particle const &p1, Particle const &p2,
195 Utils::Vector3d const &d, double dist,
196 double dist2) const {
197 if (p1.dipm() == 0. or p2.dipm() == 0. or dist >= dp3m_params.r_cut or
198 dist <= 0.)
199 return {};
200
201 auto const dip1 = p1.calc_dip();
202 auto const dip2 = p2.calc_dip();
203
204 auto const alpsq = dp3m_params.alpha * dp3m_params.alpha;
205 auto const adist = dp3m_params.alpha * dist;
206
207#if USE_ERFC_APPROXIMATION
208 auto const erfc_part_ri = Utils::AS_erfc_part(adist) / dist;
209#else
210 auto const erfc_part_ri = erfc(adist) / dist;
211#endif
212
213 // Calculate scalar multiplications for vectors mi, mj, rij
214 auto const mimj = dip1 * dip2;
215 auto const mir = dip1 * d;
216 auto const mjr = dip2 * d;
217
218 auto const coeff = 2. * dp3m_params.alpha * std::numbers::inv_sqrtpi;
219 auto const dist2i = 1. / dist2;
220 auto const exp_adist2 = exp(-Utils::sqr(adist));
221
222 auto const B_r = (dp3m_params.accuracy > 5e-06)
223 ? dist2i * (erfc_part_ri + coeff) * exp_adist2
224 : dist2i * (erfc(adist) / dist + coeff * exp_adist2);
225 auto const C_r = (3. * B_r + 2. * alpsq * coeff * exp_adist2) * dist2i;
226
227 return prefactor * (mimj * B_r - mir * mjr * C_r);
228 }
229
230protected:
231 /** Calculate self-energy in k-space. */
232 virtual double calc_average_self_energy_k_space() const = 0;
233
234 /** Calculate energy correction that minimizes the error.
235 * This quantity is only calculated once and is cached.
236 */
237 virtual void calc_energy_correction() = 0;
238
239 /** Calculate the influence function for the dipolar forces and torques. */
241
242 /** Calculate the influence function for the dipolar energy. */
244
245 /** Compute the dipolar surface terms */
246 virtual double calc_surface_term(bool force_flag, bool energy_flag,
247 ParticleRange const &particles) = 0;
248
249 /** Checks for correctness of the k-space cutoff. */
250 void sanity_checks_boxl() const;
251 void sanity_checks_node_grid() const;
252 void sanity_checks_periodicity() const;
253 void sanity_checks_cell_structure() const;
254
255 virtual void scaleby_box_l() = 0;
256
257#ifdef ESPRESSO_NPT
258 /** Update the NpT virial */
259 virtual void npt_add_virial_contribution(double energy) const = 0;
260#endif
261};
262
263std::shared_ptr<DipolarP3M>
265 TuningParameters const &tuning_params, double prefactor,
266 bool single_precision, Arch arch);
267
268#endif // ESPRESSO_DP3M
Vector implementation and trait types for boost qvm interoperability.
double prefactor
Magnetostatics prefactor.
A range of particles.
__device__ void vector_product(float const *a, float const *b, float *out)
std::shared_ptr< DipolarP3M > new_dipolar_p3m_heffte(P3MParameters &&p3m_params, TuningParameters const &tuning_params, double prefactor, bool single_precision, Arch arch)
constexpr T AS_erfc_part(T d)
Approximate by applying a formula from chapter 7.
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
Common functions for dipolar and charge P3M.
Arch
P3M kernel architecture.
Dipolar P3M solver.
Definition dp3m.hpp:55
void sanity_checks_boxl() const
Checks for correctness of the k-space cutoff.
virtual void init()=0
Recalculate all derived parameters.
virtual bool is_gpu() const noexcept=0
void sanity_checks() const
Definition dp3m.hpp:79
virtual void scaleby_box_l()=0
virtual void tune()=0
Tune dipolar P3M parameters to desired accuracy.
virtual void npt_add_virial_contribution(double energy) const =0
Update the NpT virial.
virtual void calc_energy_correction()=0
Calculate energy correction that minimizes the error.
void on_node_grid_change() const
Definition dp3m.hpp:70
virtual bool is_double_precision() const noexcept=0
void on_boxl_change()
Recalculate all box-length-dependent parameters.
Definition dp3m.hpp:69
void sanity_checks_cell_structure() const
virtual double long_range_energy(ParticleRange const &particles)=0
Compute the k-space part of energies.
virtual ~DipolarP3M()=default
virtual void dipole_assign(ParticleRange const &particles)=0
Assign the physical dipoles using the tabulated assignment function.
P3MParameters const & dp3m_params
Definition dp3m.hpp:56
double pair_energy(Particle const &p1, Particle const &p2, Utils::Vector3d const &d, double dist, double dist2) const
Calculate real-space contribution of dipolar pair energy.
Definition dp3m.hpp:194
virtual void on_activation()=0
virtual void calc_influence_function_force()=0
Calculate the influence function for the dipolar forces and torques.
virtual double calc_average_self_energy_k_space() const =0
Calculate self-energy in k-space.
virtual bool is_tuned() const noexcept=0
void sanity_checks_periodicity() const
ParticleForce pair_force(double d1d2, Utils::Vector3d const &dip1, Utils::Vector3d const &dip2, Utils::Vector3d const &d, double dist, double dist2) const
Calculate real-space contribution of p3m dipolar pair forces and torques.
Definition dp3m.hpp:138
DipolarP3M(P3MParameters const &dp3m_params)
Definition dp3m.hpp:59
void sanity_checks_node_grid() const
void on_periodicity_change() const
Definition dp3m.hpp:71
virtual void count_magnetic_particles()=0
Count the number of magnetic particles and calculate the sum of the squared dipole moments.
virtual double calc_surface_term(bool force_flag, bool energy_flag, ParticleRange const &particles)=0
Compute the dipolar surface terms.
void on_cell_structure_change()
Definition dp3m.hpp:72
virtual void calc_influence_function_energy()=0
Calculate the influence function for the dipolar energy.
virtual void add_long_range_forces(ParticleRange const &particles)=0
Compute the k-space part of forces.
Structure to hold P3M parameters and some dependent variables.
double alpha
unscaled alpha_L for use with fast inline functions only
double accuracy
accuracy of the actual parameter set.
double r_cut
unscaled r_cut_iL for use with fast inline functions only
Force information on a particle.
Definition Particle.hpp:345
Struct holding all information for one particle.
Definition Particle.hpp:450
auto calc_dip() const
Definition Particle.hpp:550
auto const & dipm() const
Definition Particle.hpp:548