ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
coulomb.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config/config.hpp"
21
23
24#ifdef ELECTROSTATICS
25
27
28#include "ParticleRange.hpp"
30#include "actor/visitors.hpp"
32#include "communication.hpp"
34#include "errorhandling.hpp"
35#include "system/System.hpp"
36
37#include <utils/Vector.hpp>
39#include <utils/constants.hpp>
40#include <utils/demangle.hpp>
41
42#include <boost/accumulators/accumulators.hpp>
43#include <boost/accumulators/statistics/sum_kahan.hpp>
44#include <boost/mpi/collectives/broadcast.hpp>
45#include <boost/mpi/collectives/gather.hpp>
46
47#include <algorithm>
48#include <cassert>
49#include <cmath>
50#include <cstdio>
51#include <iomanip>
52#include <limits>
53#include <memory>
54#include <optional>
55#include <sstream>
56#include <stdexcept>
57#include <type_traits>
58#include <variant>
59#include <vector>
60
61namespace Coulomb {
62
64 impl = std::make_unique<Implementation>();
66}
67
69
71 if (impl->solver) {
72 std::visit([](auto const &ptr) { ptr->sanity_checks(); }, *impl->solver);
73 }
74}
75
78 if (impl->solver) {
79 visit_try_catch([](auto &ptr) { ptr->init(); }, *impl->solver);
80 }
81}
82
84 if (impl->solver) {
85 visit_try_catch([](auto &ptr) { ptr->on_boxl_change(); }, *impl->solver);
86 }
87}
88
90 if (impl->solver) {
91 std::visit([](auto &ptr) { ptr->on_node_grid_change(); }, *impl->solver);
92 }
93}
94
96 if (impl->solver) {
97 visit_try_catch([](auto &ptr) { ptr->on_periodicity_change(); },
98 *impl->solver);
99 }
100}
101
103 if (impl->solver) {
104 visit_try_catch([](auto &ptr) { ptr->on_cell_structure_change(); },
105 *impl->solver);
106 }
107}
108
110 explicit LongRangePressure(ParticleRange const &particles)
111 : m_particles{particles} {}
112
113#ifdef P3M
114 auto operator()(std::shared_ptr<CoulombP3M> const &actor) const {
115 return actor->long_range_pressure(m_particles);
116 }
117#endif // P3M
118
119 auto operator()(std::shared_ptr<DebyeHueckel> const &) const {
120 return Utils::Vector9d{};
121 }
122
123 auto operator()(std::shared_ptr<ReactionField> const &) const {
124 return Utils::Vector9d{};
125 }
126
127 template <typename T,
128 std::enable_if_t<!traits::has_pressure<T>::value> * = nullptr>
129 auto operator()(std::shared_ptr<T> const &) const {
130 runtimeWarningMsg() << "Pressure calculation not implemented by "
131 << "electrostatics method " << Utils::demangle<T>();
132 return Utils::Vector9d{};
133 }
134
135private:
136 ParticleRange const &m_particles;
137};
138
141 if (impl->solver) {
142 return std::visit(LongRangePressure(particles), *impl->solver);
143 }
144 return {};
145}
146
148#ifdef P3M
149 auto operator()(std::shared_ptr<CoulombP3M> const &actor) const {
150 return actor->p3m.params.r_cut;
151 }
152 auto
153 operator()(std::shared_ptr<ElectrostaticLayerCorrection> const &actor) const {
154 return std::max(actor->elc.space_layer,
155 std::visit(*this, actor->base_solver));
156 }
157#endif // P3M
158#ifdef MMM1D_GPU
159 auto operator()(std::shared_ptr<CoulombMMM1DGpu> const &) const {
160 return std::numeric_limits<double>::infinity();
161 }
162#endif // MMM1D_GPU
163 auto operator()(std::shared_ptr<CoulombMMM1D> const &) const {
164 return std::numeric_limits<double>::infinity();
165 }
166#ifdef SCAFACOS
167 auto operator()(std::shared_ptr<CoulombScafacos> const &actor) const {
168 return actor->get_r_cut();
169 }
170#endif // SCAFACOS
171 auto operator()(std::shared_ptr<ReactionField> const &actor) const {
172 return actor->r_cut;
173 }
174 auto operator()(std::shared_ptr<DebyeHueckel> const &actor) const {
175 return actor->r_cut;
176 }
177};
178
179double Solver::cutoff() const {
180 if (impl->solver) {
181 return std::visit(ShortRangeCutoff(), *impl->solver);
182 }
183 return -1.0;
184}
185
187 template <typename T> void operator()(std::shared_ptr<T> const &) const {}
188
189#ifdef P3M
190 void operator()(std::shared_ptr<CoulombP3M> const &actor) const {
191 actor->count_charged_particles();
192 }
193 void
194 operator()(std::shared_ptr<ElectrostaticLayerCorrection> const &actor) const {
195 std::visit(*this, actor->base_solver);
196 }
197#endif // P3M
198};
199
202 if (impl->solver) {
203 std::visit(EventOnObservableCalc(), *impl->solver);
204 }
206 }
207}
208
210 explicit LongRangeForce(ParticleRange const &particles)
211 : m_particles(particles) {}
212
213#ifdef P3M
214 void operator()(std::shared_ptr<CoulombP3M> const &actor) const {
215 actor->add_long_range_forces(m_particles);
216 }
217#ifdef CUDA
218 void operator()(std::shared_ptr<CoulombP3MGPU> const &actor) const {
219 actor->add_long_range_forces(m_particles);
220 }
221#endif // CUDA
222 void
223 operator()(std::shared_ptr<ElectrostaticLayerCorrection> const &actor) const {
224 actor->add_long_range_forces(m_particles);
225 }
226#endif // P3M
227#ifdef MMM1D_GPU
228 void operator()(std::shared_ptr<CoulombMMM1DGpu> const &actor) const {
229 actor->add_long_range_forces();
230 }
231#endif
232#ifdef SCAFACOS
233 void operator()(std::shared_ptr<CoulombScafacos> const &actor) const {
234 actor->add_long_range_forces();
235 }
236#endif
237 /* Several algorithms only provide near-field kernels */
238 void operator()(std::shared_ptr<CoulombMMM1D> const &) const {}
239 void operator()(std::shared_ptr<DebyeHueckel> const &) const {}
240 void operator()(std::shared_ptr<ReactionField> const &) const {}
241
242private:
243 ParticleRange const &m_particles;
244};
245
247 explicit LongRangeEnergy(ParticleRange const &particles)
248 : m_particles(particles) {}
249
250#ifdef P3M
251 auto operator()(std::shared_ptr<CoulombP3M> const &actor) const {
252 return actor->long_range_energy(m_particles);
253 }
254 auto
255 operator()(std::shared_ptr<ElectrostaticLayerCorrection> const &actor) const {
256 return actor->long_range_energy(m_particles);
257 }
258#endif // P3M
259#ifdef MMM1D_GPU
260 auto operator()(std::shared_ptr<CoulombMMM1DGpu> const &actor) const {
261 actor->add_long_range_energy();
262 return 0.;
263 }
264#endif // MMM1D_GPU
265#ifdef SCAFACOS
266 auto operator()(std::shared_ptr<CoulombScafacos> const &actor) const {
267 return actor->long_range_energy();
268 }
269#endif
270 /* Several algorithms only provide near-field kernels */
271 auto operator()(std::shared_ptr<CoulombMMM1D> const &) const { return 0.; }
272 auto operator()(std::shared_ptr<DebyeHueckel> const &) const { return 0.; }
273 auto operator()(std::shared_ptr<ReactionField> const &) const { return 0.; }
274
275private:
276 ParticleRange const &m_particles;
277};
278
279void Solver::calc_long_range_force(ParticleRange const &particles) const {
280 if (impl->solver) {
281 std::visit(LongRangeForce(particles), *impl->solver);
282 }
283}
284
285double Solver::calc_energy_long_range(ParticleRange const &particles) const {
286 if (impl->solver) {
287 return std::visit(LongRangeEnergy(particles), *impl->solver);
288 }
289 return 0.;
290}
291
292/** @brief Compute the net charge rescaled by the smallest non-zero charge. */
293static auto calc_charge_excess_ratio(std::vector<double> const &charges) {
294 using namespace boost::accumulators;
295 using KahanSum = accumulator_set<double, features<tag::sum_kahan>>;
296
297 KahanSum q_sum;
298 auto q_min = std::numeric_limits<double>::infinity();
299
300 for (auto const q : charges) {
301 if (q != 0.) {
302 q_sum(q);
303 q_min = std::min(q_min, std::abs(q));
304 }
305 }
306
307 return std::abs(sum_kahan(q_sum)) / q_min;
308}
309
311 double relative_tolerance) {
312 // collect non-zero particle charges from all nodes
313 std::vector<double> local_charges;
314 for (auto const &p : system.cell_structure->local_particles()) {
315 local_charges.push_back(p.q());
316 }
317 std::vector<std::vector<double>> node_charges;
318 boost::mpi::gather(comm_cart, local_charges, node_charges, 0);
319
320 // run Kahan sum on charges
321 auto excess_ratio = 0.;
322 if (this_node == 0) {
323 auto charges = std::move(local_charges);
324 for (auto it = ++node_charges.begin(); it != node_charges.end(); ++it) {
325 charges.insert(charges.end(), it->begin(), it->end());
326 }
327 excess_ratio = calc_charge_excess_ratio(charges);
328 }
329 boost::mpi::broadcast(comm_cart, excess_ratio, 0);
330
331 if (excess_ratio >= relative_tolerance) {
332 std::ostringstream serializer;
333 serializer << std::scientific << std::setprecision(4);
334 serializer << excess_ratio;
335 throw std::runtime_error(
336 "The system is not charge neutral. Please neutralize the system "
337 "before adding a new actor by adding the corresponding counterions "
338 "to the system. Alternatively you can turn off the electroneutrality "
339 "check by supplying check_neutrality=False when creating the actor. "
340 "In this case you may be simulating a non-neutral system which will "
341 "affect physical observables like e.g. the pressure, the chemical "
342 "potentials of charged species or potential energies of the system. "
343 "Since simulations of non charge neutral systems are special please "
344 "make sure you know what you are doing. The relative charge excess "
345 "was " +
346 serializer.str());
347 }
348}
349
350} // namespace Coulomb
351#endif // ELECTROSTATICS
Vector implementation and trait types for boost qvm interoperability.
A range of particles.
Main system class.
std::shared_ptr< CellStructure > cell_structure
Coulomb::Solver coulomb
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
This file contains the defaults for ESPResSo.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeWarningMsg()
ICC is a method that allows to take into account the influence of arbitrarily shaped dielectric inter...
void check_charge_neutrality(System::System const &system, double relative_tolerance)
Check if the system is charge-neutral.
Definition coulomb.cpp:310
static auto calc_charge_excess_ratio(std::vector< double > const &charges)
Compute the net charge rescaled by the smallest non-zero charge.
Definition coulomb.cpp:293
Solver const & get_coulomb()
Definition coulomb.cpp:68
System & get_system()
void operator()(std::shared_ptr< T > const &) const
Definition coulomb.cpp:187
void operator()(std::shared_ptr< ElectrostaticLayerCorrection > const &actor) const
Definition coulomb.cpp:194
void operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:190
auto operator()(std::shared_ptr< ReactionField > const &) const
Definition coulomb.cpp:273
LongRangeEnergy(ParticleRange const &particles)
Definition coulomb.cpp:247
auto operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:251
auto operator()(std::shared_ptr< CoulombMMM1D > const &) const
Definition coulomb.cpp:271
auto operator()(std::shared_ptr< CoulombMMM1DGpu > const &actor) const
Definition coulomb.cpp:260
auto operator()(std::shared_ptr< ElectrostaticLayerCorrection > const &actor) const
Definition coulomb.cpp:255
auto operator()(std::shared_ptr< CoulombScafacos > const &actor) const
Definition coulomb.cpp:266
auto operator()(std::shared_ptr< DebyeHueckel > const &) const
Definition coulomb.cpp:272
void operator()(std::shared_ptr< CoulombP3MGPU > const &actor) const
Definition coulomb.cpp:218
void operator()(std::shared_ptr< ReactionField > const &) const
Definition coulomb.cpp:240
LongRangeForce(ParticleRange const &particles)
Definition coulomb.cpp:210
void operator()(std::shared_ptr< CoulombScafacos > const &actor) const
Definition coulomb.cpp:233
void operator()(std::shared_ptr< CoulombMMM1D > const &) const
Definition coulomb.cpp:238
void operator()(std::shared_ptr< CoulombMMM1DGpu > const &actor) const
Definition coulomb.cpp:228
void operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:214
void operator()(std::shared_ptr< DebyeHueckel > const &) const
Definition coulomb.cpp:239
void operator()(std::shared_ptr< ElectrostaticLayerCorrection > const &actor) const
Definition coulomb.cpp:223
LongRangePressure(ParticleRange const &particles)
Definition coulomb.cpp:110
auto operator()(std::shared_ptr< ReactionField > const &) const
Definition coulomb.cpp:123
auto operator()(std::shared_ptr< DebyeHueckel > const &) const
Definition coulomb.cpp:119
auto operator()(std::shared_ptr< T > const &) const
Definition coulomb.cpp:129
auto operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:114
auto operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:149
auto operator()(std::shared_ptr< CoulombMMM1D > const &) const
Definition coulomb.cpp:163
auto operator()(std::shared_ptr< ElectrostaticLayerCorrection > const &actor) const
Definition coulomb.cpp:153
auto operator()(std::shared_ptr< ReactionField > const &actor) const
Definition coulomb.cpp:171
auto operator()(std::shared_ptr< CoulombMMM1DGpu > const &) const
Definition coulomb.cpp:159
auto operator()(std::shared_ptr< DebyeHueckel > const &actor) const
Definition coulomb.cpp:174
auto operator()(std::shared_ptr< CoulombScafacos > const &actor) const
Definition coulomb.cpp:167
void on_observable_calc()
Definition coulomb.cpp:200
double cutoff() const
Definition coulomb.cpp:179
void sanity_checks() const
Definition coulomb.cpp:70
void on_cell_structure_change()
Definition coulomb.cpp:102
void on_periodicity_change()
Definition coulomb.cpp:95
void calc_long_range_force(ParticleRange const &particles) const
Definition coulomb.cpp:279
void on_node_grid_change()
Definition coulomb.cpp:89
Utils::Vector9d calc_pressure_long_range(ParticleRange const &particles) const
Definition coulomb.cpp:140
void on_coulomb_change()
Definition coulomb.cpp:76
std::unique_ptr< Implementation > impl
Pointer-to-implementation.
void on_boxl_change()
Definition coulomb.cpp:83
bool reinit_on_observable_calc
Whether to reinitialize the solver on observable calculation.
double calc_energy_long_range(ParticleRange const &particles) const
Definition coulomb.cpp:285
void visit_try_catch(Visitor &&visitor, Variant &actor)
Run a kernel on a variant and queue errors.