Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
dlc.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 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#include "config/config.hpp"
23
24#ifdef DIPOLES
25
27
31#include "p3m/common.hpp"
32
33#include "BoxGeometry.hpp"
34#include "Particle.hpp"
36#include "communication.hpp"
37#include "errorhandling.hpp"
38#include "system/System.hpp"
39
40#include <utils/math/sqr.hpp>
41
42#include <boost/mpi/collectives/all_reduce.hpp>
43#include <boost/mpi/collectives/reduce.hpp>
44#include <boost/mpi/operations.hpp>
45
46#include <mpi.h>
47
48#include <algorithm>
49#include <cassert>
50#include <cmath>
51#include <cstdio>
52#include <functional>
53#include <limits>
54#include <numbers>
55#include <numeric>
56#include <stdexcept>
57#include <variant>
58#include <vector>
59
60void DipolarLayerCorrection::check_gap(Particle const &p) const {
61 if (p.dipm() != 0.) {
62 auto const z = p.pos()[2];
63 if (z < 0. or z > dlc.box_h) {
64 runtimeErrorMsg() << "Particle " << p.id() << " entered DLC gap region "
65 << "by " << z - ((z < 0.) ? 0. : dlc.box_h);
66 }
67 }
68}
69
70/** Calculate the maximal dipole moment in the system */
71static double calc_mu_max(System::System const &system) {
72 auto const local_particles = system.cell_structure->local_particles();
73 auto const mu_max_local = std::accumulate(
74 local_particles.begin(), local_particles.end(), 0.,
75 [](double mu, Particle const &p) { return std::max(mu, p.dipm()); });
76
77 return boost::mpi::all_reduce(comm_cart, mu_max_local,
78 boost::mpi::maximum<double>());
79}
80
81static double g1_DLC_dip(double g, double x) {
82 auto const c = g / x;
83 auto const cc2 = c * c;
84 auto const x3 = x * x * x;
85 auto const a = g * g * g / x + 1.5 * cc2 + 1.5 * g / x3 + 0.75 / (x3 * x);
86 return a;
87}
88
89static double g2_DLC_dip(double g, double x) {
90 auto const x2 = x * x;
91 auto const a = g * g / x + 2.0 * g / x2 + 2.0 / (x2 * x);
92 return a;
93}
94
95/** Compute the box magnetic dipole. */
97
98 Utils::Vector3d local_dip{};
99 for (auto const &p : particles) {
100 if (p.dipm() != 0.) {
101 local_dip += p.calc_dip();
102 }
103 }
104
105 return boost::mpi::all_reduce(comm_cart, local_dip, std::plus<>());
106}
107
108/**
109 * @brief Compute the dipolar force and torque corrections.
110 * Algorithm implemented accordingly to @cite brodka04a.
111 */
112static void dipolar_force_corrections(int kcut,
113 std::vector<Utils::Vector3d> &fs,
114 std::vector<Utils::Vector3d> &ts,
115 ParticleRange const &particles,
116 BoxGeometry const &box_geo) {
117 auto const facux = 2. * std::numbers::pi * box_geo.length_inv()[0];
118 auto const facuy = 2. * std::numbers::pi * box_geo.length_inv()[1];
119
120 auto const n_local_particles = particles.size();
121 std::vector<double> ReSjp(n_local_particles);
122 std::vector<double> ReSjm(n_local_particles);
123 std::vector<double> ImSjp(n_local_particles);
124 std::vector<double> ImSjm(n_local_particles);
125 std::vector<double> ReGrad_Mup(n_local_particles);
126 std::vector<double> ImGrad_Mup(n_local_particles);
127 std::vector<double> ReGrad_Mum(n_local_particles);
128 std::vector<double> ImGrad_Mum(n_local_particles);
129
130 for (int ix = -kcut; ix <= +kcut; ix++) {
131 for (int iy = -kcut; iy <= +kcut; iy++) {
132 if (ix == 0 and iy == 0) {
133 continue;
134 }
135 auto const gx = static_cast<double>(ix) * facux;
136 auto const gy = static_cast<double>(iy) * facuy;
137 auto const gr = sqrt(gx * gx + gy * gy);
138
139 // We assume short slab direction is in the z-direction
140 auto const fa1 = 1. / (gr * (exp(gr * box_geo.length()[2]) - 1.));
141
142 // ... Compute S+,(S+)*,S-,(S-)*, and Spj,Smj for the current g
143
144 std::size_t ip = 0;
145 double S[4] = {0., 0., 0., 0.}; // S of Brodka method, or is S[4] =
146 // {Re(S+), Im(S+), Re(S-), Im(S-)}
147 for (auto const &p : particles) {
148 if (p.dipm() != 0.) {
149 auto const &pos = p.pos();
150 auto const dip = p.calc_dip();
151
152 auto const a = gx * dip[0] + gy * dip[1];
153 auto const b = gr * dip[2];
154 auto const er = gx * pos[0] + gy * pos[1];
155 auto const ez = gr * pos[2];
156 auto const c = cos(er);
157 auto const d = sin(er);
158 auto const f = exp(ez);
159
160 ReSjp[ip] = (b * c - a * d) * f;
161 ImSjp[ip] = (c * a + b * d) * f;
162 ReSjm[ip] = (-b * c - a * d) / f;
163 ImSjm[ip] = (c * a - b * d) / f;
164 ReGrad_Mup[ip] = c * f;
165 ReGrad_Mum[ip] = c / f;
166 ImGrad_Mup[ip] = d * f;
167 ImGrad_Mum[ip] = d / f;
168
169 S[0] += ReSjp[ip];
170 S[1] += ImSjp[ip];
171 S[2] += ReSjm[ip];
172 S[3] += ImSjm[ip];
173 }
174 ip++;
175 }
176
177 MPI_Allreduce(MPI_IN_PLACE, S, 4, MPI_DOUBLE, MPI_SUM, comm_cart);
178
179 // ... Now we can compute the contributions to E,Fj,Ej for the current
180 // g-value
181 ip = 0;
182 for (auto &p : particles) {
183 if (p.dipm() != 0.) {
184 {
185 // compute contributions to the forces
186 auto const s1 = -(-ReSjp[ip] * S[3] + ImSjp[ip] * S[2]);
187 auto const s2 = +(ReSjm[ip] * S[1] - ImSjm[ip] * S[0]);
188 auto const s3 = -(-ReSjm[ip] * S[1] + ImSjm[ip] * S[0]);
189 auto const s4 = +(ReSjp[ip] * S[3] - ImSjp[ip] * S[2]);
190
191 auto const s1z = +(ReSjp[ip] * S[2] + ImSjp[ip] * S[3]);
192 auto const s2z = -(ReSjm[ip] * S[0] + ImSjm[ip] * S[1]);
193 auto const s3z = -(ReSjm[ip] * S[0] + ImSjm[ip] * S[1]);
194 auto const s4z = +(ReSjp[ip] * S[2] + ImSjp[ip] * S[3]);
195
196 auto const ss = s1 + s2 + s3 + s4;
197 fs[ip][0] += fa1 * gx * ss;
198 fs[ip][1] += fa1 * gy * ss;
199 fs[ip][2] += fa1 * gr * (s1z + s2z + s3z + s4z);
200 }
201 {
202 // compute contributions to the electrical field
203 auto const s1 = -(-ReGrad_Mup[ip] * S[3] + ImGrad_Mup[ip] * S[2]);
204 auto const s2 = +(ReGrad_Mum[ip] * S[1] - ImGrad_Mum[ip] * S[0]);
205 auto const s3 = -(-ReGrad_Mum[ip] * S[1] + ImGrad_Mum[ip] * S[0]);
206 auto const s4 = +(ReGrad_Mup[ip] * S[3] - ImGrad_Mup[ip] * S[2]);
207
208 auto const s1z = +(ReGrad_Mup[ip] * S[2] + ImGrad_Mup[ip] * S[3]);
209 auto const s2z = -(ReGrad_Mum[ip] * S[0] + ImGrad_Mum[ip] * S[1]);
210 auto const s3z = -(ReGrad_Mum[ip] * S[0] + ImGrad_Mum[ip] * S[1]);
211 auto const s4z = +(ReGrad_Mup[ip] * S[2] + ImGrad_Mup[ip] * S[3]);
212
213 auto const ss = s1 + s2 + s3 + s4;
214 ts[ip][0] += fa1 * gx * ss;
215 ts[ip][1] += fa1 * gy * ss;
216 ts[ip][2] += fa1 * gr * (s1z + s2z + s3z + s4z);
217 }
218 }
219 ++ip;
220 }
221 }
222 }
223
224 // Convert from the corrections to the electrical field to the corrections
225 // for the torques
226 std::size_t ip = 0;
227 for (auto const &p : particles) {
228 if (p.dipm() != 0.) {
229 ts[ip] = vector_product(p.calc_dip(), ts[ip]);
230 }
231 ++ip;
232 }
233
234 // Multiply by the factors we have left during the loops
235
236 auto const piarea =
237 std::numbers::pi * box_geo.length_inv()[0] * box_geo.length_inv()[1];
238 for (std::size_t j = 0; j < n_local_particles; ++j) {
239 fs[j] *= piarea;
240 ts[j] *= piarea;
241 }
242}
243
244/**
245 * @brief Compute the dipolar DLC energy correction.
246 * Algorithm implemented accordingly to @cite brodka04a.
247 */
248static double dipolar_energy_correction(int kcut,
249 ParticleRange const &particles,
250 BoxGeometry const &box_geo) {
251 auto const facux = 2. * std::numbers::pi * box_geo.length_inv()[0];
252 auto const facuy = 2. * std::numbers::pi * box_geo.length_inv()[1];
253
254 double energy = 0.;
255 double sum_S[4] = {0., 0., 0., 0.};
256 for (int ix = -kcut; ix <= +kcut; ix++) {
257 for (int iy = -kcut; iy <= +kcut; iy++) {
258 if ((ix == 0 && iy == 0)) {
259 continue;
260 }
261 auto const gx = static_cast<double>(ix) * facux;
262 auto const gy = static_cast<double>(iy) * facuy;
263 auto const gr = sqrt(gx * gx + gy * gy);
264
265 // We assume short slab direction is in the z-direction
266 auto const fa1 = 1. / (gr * (exp(gr * box_geo.length()[2]) - 1.));
267
268 // ... Compute S+,(S+)*,S-,(S-)*, and Spj,Smj for the current g
269
270 double S[4] = {0., 0., 0., 0.}; // S of Brodka method, or is S[4] =
271 // {Re(S+), Im(S+), Re(S-), Im(S-)}
272 for (auto const &p : particles) {
273 if (p.dipm() != 0.) {
274 auto const &pos = p.pos();
275 auto const dip = p.calc_dip();
276
277 auto const a = gx * dip[0] + gy * dip[1];
278 auto const b = gr * dip[2];
279 auto const er = gx * pos[0] + gy * pos[1];
280 auto const ez = gr * pos[2];
281 auto const c = cos(er);
282 auto const d = sin(er);
283 auto const f = exp(ez);
284
285 S[0] += (b * c - a * d) * f;
286 S[1] += (c * a + b * d) * f;
287 S[2] += (-b * c - a * d) / f;
288 S[3] += (c * a - b * d) / f;
289 }
290 }
291 boost::mpi::reduce(comm_cart, S, 4, sum_S, std::plus<>(), 0);
292
293 // compute contribution to the energy
294 // s2=(ReSm*ReSp+ImSm*ImSp); s2=s1!!!
295 energy += fa1 * 2. * (sum_S[0] * sum_S[2] + sum_S[1] * sum_S[3]);
296 }
297 }
298
299 auto const piarea =
300 std::numbers::pi * box_geo.length_inv()[0] * box_geo.length_inv()[1];
301 energy *= -piarea;
302 return (this_node == 0) ? energy : 0.;
303}
304
306 ParticleRange const &particles) const {
307 assert(dlc.far_cut > 0.);
308 auto const &box_geo = *get_system().box_geo;
309 auto const volume = box_geo.volume();
310 auto const correc = 4. * std::numbers::pi / volume;
311
312 // --- Create arrays that should contain the corrections to
313 // the forces and torques, and set them to zero.
314 std::vector<Utils::Vector3d> dip_DLC_f(particles.size());
315 std::vector<Utils::Vector3d> dip_DLC_t(particles.size());
316
317 //---- Compute the corrections ----------------------------------
318
319 // First the DLC correction
320 auto const kcut = static_cast<int>(std::round(dlc.far_cut));
321 dipolar_force_corrections(kcut, dip_DLC_f, dip_DLC_t, particles, box_geo);
322
323 // Now we compute the correction like Yeh and Klapp to take into account
324 // the fact that you are using a 3D PBC method which uses spherical
325 // summation instead of slab-wise summation.
326 // Slab-wise summation is the one required to apply DLC correction.
327 // This correction is often called SDC = Shape Dependent Correction.
328 // See @cite brodka04a.
329
330 auto const box_dip = calc_slab_dipole(particles);
331
332 // --- Transfer the computed corrections to the Forces, Energy and torques
333 // of the particles
334
335 std::size_t ip = 0;
336 for (auto &p : particles) {
337 check_gap(p);
338
339 if (p.dipm() != 0.) {
340 // SDC correction term is zero for the forces
341 p.force() += prefactor * dip_DLC_f[ip];
342
343 auto const dip = p.calc_dip();
344 // SDC correction for the torques
345 auto d = Utils::Vector3d{0., 0., -correc * box_dip[2]};
346#ifdef DP3M
348 d += correc * epsilon_correction * box_dip;
349 }
350#endif
351 p.torque() += prefactor * (dip_DLC_t[ip] + vector_product(dip, d));
352 }
353 ++ip;
354 }
355}
356
358 ParticleRange const &particles) const {
359 assert(dlc.far_cut > 0.);
360 auto const &box_geo = *get_system().box_geo;
361 auto const volume = box_geo.volume();
362 auto const pref = prefactor * 2. * std::numbers::pi / volume;
363
364 // Check if particles aren't in the forbidden gap region
365 // This loop is needed, because there is no other guaranteed
366 // single pass over all particles in this function.
367 for (auto const &p : particles) {
368 check_gap(p);
369 }
370
371 //---- Compute the corrections ----------------------------------
372
373 // First the DLC correction
374 auto const k_cut = static_cast<int>(std::round(dlc.far_cut));
375 auto dip_DLC_energy =
376 prefactor * dipolar_energy_correction(k_cut, particles, box_geo);
377
378 // Now we compute the correction like Yeh and Klapp to take into account
379 // the fact that you are using a 3D PBC method which uses spherical
380 // summation instead of slab-wise summation.
381 // Slab-wise summation is the one required to apply DLC correction.
382 // This correction is often called SDC = Shape Dependent Correction.
383 // See @cite brodka04a.
384
385 auto const box_dip = calc_slab_dipole(particles);
386
387 if (this_node == 0) {
388 dip_DLC_energy += pref * Utils::sqr(box_dip[2]);
389#ifdef DP3M
391 dip_DLC_energy -= pref * epsilon_correction * box_dip.norm2();
392 }
393#endif
394 return dip_DLC_energy;
395 }
396 return 0.;
397}
398
399static int count_magnetic_particles(System::System const &system) {
400 int local_n = 0;
401
402 for (auto const &p : system.cell_structure->local_particles()) {
403 if (p.dipm() != 0.) {
404 local_n++;
405 }
406 }
407
408 return boost::mpi::all_reduce(comm_cart, local_n, std::plus<>());
409}
410
411/** Compute the cut-off in the DLC dipolar part to get a certain accuracy.
412 * We assume particles to have all the same value of the dipolar momentum
413 * modulus, which is taken as the largest value of mu inside the system.
414 * If we assume the gap has a width @c gap_size (within
415 * which there is no particles): <tt>Lz = h + gap_size</tt>
416 */
417double DipolarLayerCorrection::tune_far_cut() const {
418 auto const &system = get_system();
419 /* we take the maximum dipole in the system, to be sure that the errors
420 * in the other case will be equal or less than for this one */
421 auto const mu_max_sq = Utils::sqr(calc_mu_max(system));
422 auto const &box_geo = *system.box_geo;
423 auto const lx = box_geo.length()[0];
424 auto const ly = box_geo.length()[1];
425 auto const lz = box_geo.length()[2];
426
427 if (std::abs(lx - ly) > 0.001) {
428 throw std::runtime_error("DLC tuning: box size in x direction is "
429 "different from y direction. The tuning "
430 "formula requires both to be equal.");
431 }
432
433 auto constexpr limitkc = 200;
434 auto constexpr exp_max = +709.8; // for IEEE-compatible double
435 auto constexpr exp_min = -708.4; // for IEEE-compatible double
436 auto const log_max = std::log(std::numeric_limits<double>::max());
437 auto const piarea = std::numbers::pi / (lx * ly);
438 auto const nmp = static_cast<double>(count_magnetic_particles(system));
439 auto const h = dlc.box_h;
440 auto far_cut = -1.;
441 for (int kc = 1; kc < limitkc; kc++) {
442 auto const gc = kc * 2. * std::numbers::pi / lx;
443 auto const pref1 = g1_DLC_dip(gc, lz - h);
444 auto const pref2 = g1_DLC_dip(gc, lz + h);
445 auto const pref0 = g1_DLC_dip(gc, lz);
446 auto const exp_term = 2. * gc * h;
447 auto const log_term1 = exp_term + std::log(9. * pref1);
448 if (exp_term >= exp_max or log_term1 >= log_max or -exp_term <= exp_min) {
449 // no solution can be found at larger k values due to overflow/underflow
450 break;
451 }
452 auto const fa0 = std::sqrt(9. * std::exp(+exp_term) * pref1 +
453 9. * std::exp(-exp_term) * pref2 + 22. * pref0);
454 auto const fa1 = sqrt(0.125 * piarea) * fa0;
455 auto const fa2 = g2_DLC_dip(gc, lz);
456 auto const de = nmp * mu_max_sq / (4. * (exp(gc * lz) - 1.)) * (fa1 + fa2);
457 if (de < dlc.maxPWerror) {
458 far_cut = static_cast<double>(kc);
459 break;
460 }
461 }
462 if (far_cut <= 0.) {
463 throw std::runtime_error("DLC tuning failed: maxPWerror too small");
464 }
465 return far_cut;
466}
467
468/** @brief Lock an actor and modify its parameters. */
470 explicit AdaptSolver(DipolarLayerCorrection *this_ptr) : m_actor{this_ptr} {}
471
472 void operator()(std::shared_ptr<DipolarDirectSum> const &solver) {
473 m_actor->prefactor = solver->prefactor;
474 m_actor->epsilon = P3M_EPSILON_METALLIC;
475 }
476
477#ifdef DP3M
478 void operator()(std::shared_ptr<DipolarP3M> const &solver) {
479 m_actor->prefactor = solver->prefactor;
480 m_actor->epsilon = solver->dp3m_params.epsilon;
481 }
482#endif
483
484private:
485 DipolarLayerCorrection *m_actor;
486};
487
489 auto visitor = AdaptSolver{this};
490 std::visit(visitor, base_solver);
492 (epsilon == P3M_EPSILON_METALLIC) ? 0. : 1. / (2. * epsilon + 1.);
493}
494
495void DipolarLayerCorrection::sanity_checks_periodicity() const {
496 auto const &box_geo = *get_system().box_geo;
497 if (!box_geo.periodic(0) || !box_geo.periodic(1) || !box_geo.periodic(2)) {
498 throw std::runtime_error("DLC: requires periodicity (True, True, True)");
499 }
500}
501
502dlc_data::dlc_data(double maxPWerror, double gap_size, double far_cut)
503 : maxPWerror{maxPWerror}, gap_size{gap_size}, box_h{-1.}, far_cut{far_cut},
504 far_calculated{far_cut == -1.} {
505 if (far_cut <= 0. and not far_calculated) {
506 throw std::domain_error("Parameter 'far_cut' must be > 0");
507 }
508 if (maxPWerror <= 0.) {
509 throw std::domain_error("Parameter 'maxPWerror' must be > 0");
510 }
511 if (gap_size <= 0.) {
512 throw std::domain_error("Parameter 'gap_size' must be > 0");
513 }
514}
515
517 auto const lz = get_system().box_geo->length()[2];
518 auto const new_box_h = lz - dlc.gap_size;
519 if (new_box_h < 0.) {
520 throw std::runtime_error("DLC gap size (" + std::to_string(dlc.gap_size) +
521 ") larger than box length in z-direction (" +
522 std::to_string(lz) + ")");
523 }
524 dlc.box_h = new_box_h;
525}
526
528 BaseSolver &&solver)
529 : dlc{parameters}, base_solver{solver} {
530 adapt_solver();
531}
532
533#endif // DIPOLES
Utils::Vector3d const & length() const
Box length.
Utils::Vector3d const & length_inv() const
Inverse box length.
A range of particles.
base_type::size_type size() const
Main system class.
std::shared_ptr< CellStructure > cell_structure
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
This file contains the defaults for ESPResSo.
__device__ void vector_product(float const *a, float const *b, float *out)
static void dipolar_force_corrections(int kcut, std::vector< Utils::Vector3d > &fs, std::vector< Utils::Vector3d > &ts, ParticleRange const &particles, BoxGeometry const &box_geo)
Compute the dipolar force and torque corrections.
Definition dlc.cpp:112
static double g1_DLC_dip(double g, double x)
Definition dlc.cpp:81
static double dipolar_energy_correction(int kcut, ParticleRange const &particles, BoxGeometry const &box_geo)
Compute the dipolar DLC energy correction.
Definition dlc.cpp:248
static double g2_DLC_dip(double g, double x)
Definition dlc.cpp:89
static Utils::Vector3d calc_slab_dipole(ParticleRange const &particles)
Compute the box magnetic dipole.
Definition dlc.cpp:96
static double calc_mu_max(System::System const &system)
Calculate the maximal dipole moment in the system.
Definition dlc.cpp:71
static int count_magnetic_particles(System::System const &system)
Definition dlc.cpp:399
P3M algorithm for long-range magnetic dipole-dipole interaction.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
Vector< T, N > sqrt(Vector< T, N > const &a)
Definition Vector.hpp:358
Common functions for dipolar and charge P3M.
auto constexpr P3M_EPSILON_METALLIC
This value indicates metallic boundary conditions.
Lock an actor and modify its parameters.
Definition dlc.cpp:469
AdaptSolver(DipolarLayerCorrection *this_ptr)
Definition dlc.cpp:470
void operator()(std::shared_ptr< DipolarDirectSum > const &solver)
Definition dlc.cpp:472
void operator()(std::shared_ptr< DipolarP3M > const &solver)
Definition dlc.cpp:478
Adapt a magnetostatics solver to remove contributions from the z-direction.
Definition dlc.hpp:78
double epsilon_correction
Definition dlc.hpp:89
double energy_correction(ParticleRange const &particles) const
Calculate the dipolar energy correction.
Definition dlc.cpp:357
BaseSolver base_solver
Magnetostatics solver that is adapted.
Definition dlc.hpp:94
void add_force_corrections(ParticleRange const &particles) const
Add the dipolar force and torque corrections.
Definition dlc.cpp:305
DipolarLayerCorrection(dlc_data &&parameters, BaseSolver &&solver)
Definition dlc.cpp:527
std::variant< std::shared_ptr< DipolarP3M >, std::shared_ptr< DipolarDirectSum > > BaseSolver
Definition dlc.hpp:83
Struct holding all information for one particle.
Definition Particle.hpp:395
auto calc_dip() const
Definition Particle.hpp:495
auto const & torque() const
Definition Particle.hpp:479
auto const & dipm() const
Definition Particle.hpp:493
auto const & pos() const
Definition Particle.hpp:431
auto const & force() const
Definition Particle.hpp:435
auto const & id() const
Definition Particle.hpp:414
Parameters for the DLC method.
Definition dlc.hpp:47
bool far_calculated
Flag whether far_cut was set by the user, or calculated by ESPResSo.
Definition dlc.hpp:71
dlc_data(double maxPWerror, double gap_size, double far_cut)
Definition dlc.cpp:502
double maxPWerror
maximal pairwise error of the potential and force
Definition dlc.hpp:51
double far_cut
Cutoff of the exponential sum.
Definition dlc.hpp:65
double gap_size
Size of the empty gap.
Definition dlc.hpp:56
double box_h
Up to where particles can be found.
Definition dlc.hpp:59