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-2026 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 ESPRESSO_ELECTROSTATICS
25
27
29#include "actor/visitors.hpp"
31#include "communication.hpp"
32#include "errorhandling.hpp"
33#include "system/System.hpp"
34
35#include <utils/Vector.hpp>
36#include <utils/demangle.hpp>
38
39#include <boost/accumulators/accumulators.hpp>
40#include <boost/accumulators/statistics/sum_kahan.hpp>
41#include <boost/mpi/collectives/broadcast.hpp>
42
43#include <algorithm>
44#include <cmath>
45#include <iomanip>
46#include <limits>
47#include <memory>
48#include <optional>
49#include <sstream>
50#include <stdexcept>
51#include <variant>
52#include <vector>
53
54namespace Coulomb {
55
57 impl = std::make_unique<Implementation>();
59}
60
62 if (impl->solver) {
63 std::visit([](auto const &ptr) { ptr->sanity_checks(); }, *impl->solver);
64 }
65}
66
69 if (impl->solver) {
70 visit_try_catch([](auto &ptr) { ptr->init(); }, *impl->solver);
71 }
72}
73
75 if (impl->solver) {
76 visit_try_catch([](auto &ptr) { ptr->on_boxl_change(); }, *impl->solver);
77 }
78}
79
81 if (impl->solver) {
82 std::visit([](auto &ptr) { ptr->on_node_grid_change(); }, *impl->solver);
83 }
84}
85
87 if (impl->solver) {
88 visit_try_catch([](auto &ptr) { ptr->on_periodicity_change(); },
89 *impl->solver);
90 }
91}
92
94 if (impl->solver) {
95 visit_try_catch([](auto &ptr) { ptr->on_cell_structure_change(); },
96 *impl->solver);
97 }
98}
99
101#ifdef ESPRESSO_P3M
102 auto operator()(std::shared_ptr<CoulombP3M> const &actor) const {
103 return actor->long_range_pressure();
104 }
105#endif // ESPRESSO_P3M
106
107 auto operator()(std::shared_ptr<DebyeHueckel> const &) const {
108 return Utils::Vector9d{};
109 }
110
111 auto operator()(std::shared_ptr<ReactionField> const &) const {
112 return Utils::Vector9d{};
113 }
114
115 template <typename T>
117 auto operator()(std::shared_ptr<T> const &) const {
118 runtimeWarningMsg() << "Pressure calculation not implemented by "
119 << "electrostatics method " << Utils::demangle<T>();
120 return Utils::Vector9d{};
121 }
122};
123
125 if (impl->solver) {
126 return std::visit(LongRangePressure{}, *impl->solver);
127 }
128 return {};
129}
130
132#ifdef ESPRESSO_P3M
133 auto operator()(std::shared_ptr<CoulombP3M> const &actor) const {
134 return actor->p3m_params.r_cut;
135 }
136 auto
137 operator()(std::shared_ptr<ElectrostaticLayerCorrection> const &actor) const {
138 return std::max(actor->elc.space_layer,
139 std::visit(*this, actor->base_solver));
140 }
141#endif // ESPRESSO_P3M
142#ifdef ESPRESSO_MMM1D
143 auto operator()(std::shared_ptr<CoulombMMM1D> const &) const {
144 return std::numeric_limits<double>::infinity();
145 }
146#endif
147#ifdef ESPRESSO_SCAFACOS
148 auto operator()(std::shared_ptr<CoulombScafacos> const &actor) const {
149 return actor->get_r_cut();
150 }
151#endif // ESPRESSO_SCAFACOS
152 auto operator()(std::shared_ptr<ReactionField> const &actor) const {
153 return actor->r_cut;
154 }
155 auto operator()(std::shared_ptr<DebyeHueckel> const &actor) const {
156 return actor->r_cut;
157 }
158};
159
160double Solver::cutoff() const {
161 if (impl->solver) {
162 return std::visit(ShortRangeCutoff(), *impl->solver);
163 }
164 return inactive_cutoff;
165}
166
168 template <typename T> void operator()(std::shared_ptr<T> const &) const {}
169
170#ifdef ESPRESSO_P3M
171 void operator()(std::shared_ptr<CoulombP3M> const &actor) const {
172 actor->count_charged_particles();
173 }
174 void
175 operator()(std::shared_ptr<ElectrostaticLayerCorrection> const &actor) const {
176 std::visit(*this, actor->base_solver);
177 }
178#endif // ESPRESSO_P3M
179};
180
183 if (impl->solver) {
184 std::visit(EventOnObservableCalc(), *impl->solver);
185 }
187 }
188}
189
191 template <class Solver>
192 void operator()(std::shared_ptr<Solver> const &actor) const {
193 actor->add_long_range_forces();
194 }
195 /* Several algorithms only provide near-field kernels */
196#ifdef ESPRESSO_MMM1D
197 void operator()(std::shared_ptr<CoulombMMM1D> const &) const {}
198#endif
199 void operator()(std::shared_ptr<DebyeHueckel> const &) const {}
200 void operator()(std::shared_ptr<ReactionField> const &) const {}
201};
202
204 template <class Solver>
205 auto operator()(std::shared_ptr<Solver> const &actor) const {
206 return actor->long_range_energy();
207 }
208 /* Several algorithms only provide near-field kernels */
209#ifdef ESPRESSO_MMM1D
210 auto operator()(std::shared_ptr<CoulombMMM1D> const &) const { return 0.; }
211#endif
212 auto operator()(std::shared_ptr<DebyeHueckel> const &) const { return 0.; }
213 auto operator()(std::shared_ptr<ReactionField> const &) const { return 0.; }
214};
215
217 if (impl->solver) {
218 std::visit(LongRangeForce{}, *impl->solver);
219 }
220}
221
223 if (impl->solver) {
224 return std::visit(LongRangeEnergy{}, *impl->solver);
225 }
226 return 0.;
227}
228
229/** @brief Compute the net charge rescaled by the smallest non-zero charge. */
230static auto calc_charge_excess_ratio(std::vector<double> const &charges) {
231 using namespace boost::accumulators;
233
235 auto q_min = std::numeric_limits<double>::infinity();
236
237 for (auto const q : charges) {
238 if (q != 0.) {
239 q_sum(q);
240 q_min = std::min(q_min, std::abs(q));
241 }
242 }
243
244 return std::abs(sum_kahan(q_sum)) / q_min;
245}
246
248 double relative_tolerance) {
249 // collect non-zero particle charges from all nodes
250 std::vector<double> charges;
251 for (auto const &p : system.cell_structure->local_particles()) {
252 charges.emplace_back(p.q());
253 }
255
256 // run Kahan sum on charges
257 auto excess_ratio = 0.;
258 if (this_node == 0) {
260 }
261 boost::mpi::broadcast(comm_cart, excess_ratio, 0);
262
264 std::ostringstream serializer;
265 serializer << std::scientific << std::setprecision(4);
267 throw std::runtime_error(
268 "The system is not charge neutral. Please neutralize the system "
269 "before adding a new actor by adding the corresponding counterions "
270 "to the system. Alternatively you can turn off the electroneutrality "
271 "check by supplying check_neutrality=False when creating the actor. "
272 "In this case you may be simulating a non-neutral system which will "
273 "affect physical observables like e.g. the pressure, the chemical "
274 "potentials of charged species or potential energies of the system. "
275 "Since simulations of non charge neutral systems are special please "
276 "make sure you know what you are doing. The relative charge excess "
277 "was " +
278 serializer.str());
279 }
280}
281
282} // namespace Coulomb
283#endif // ESPRESSO_ELECTROSTATICS
Vector implementation and trait types for boost qvm interoperability.
Main system class.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
constexpr double inactive_cutoff
Special cutoff value for an inactive interaction.
Definition config.hpp:53
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeWarningMsg()
void check_charge_neutrality(System::System const &system, double relative_tolerance)
Check if the system is charge-neutral.
Definition coulomb.cpp:247
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:230
void gather_buffer(std::vector< T, Allocator > &buffer, boost::mpi::communicator const &comm, int root=0)
Gather buffer with different size on each node.
void operator()(std::shared_ptr< T > const &) const
Definition coulomb.cpp:168
void operator()(std::shared_ptr< ElectrostaticLayerCorrection > const &actor) const
Definition coulomb.cpp:175
void operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:171
auto operator()(std::shared_ptr< ReactionField > const &) const
Definition coulomb.cpp:213
auto operator()(std::shared_ptr< Solver > const &actor) const
Definition coulomb.cpp:205
auto operator()(std::shared_ptr< CoulombMMM1D > const &) const
Definition coulomb.cpp:210
auto operator()(std::shared_ptr< DebyeHueckel > const &) const
Definition coulomb.cpp:212
void operator()(std::shared_ptr< ReactionField > const &) const
Definition coulomb.cpp:200
void operator()(std::shared_ptr< CoulombMMM1D > const &) const
Definition coulomb.cpp:197
void operator()(std::shared_ptr< Solver > const &actor) const
Definition coulomb.cpp:192
void operator()(std::shared_ptr< DebyeHueckel > const &) const
Definition coulomb.cpp:199
auto operator()(std::shared_ptr< ReactionField > const &) const
Definition coulomb.cpp:111
auto operator()(std::shared_ptr< DebyeHueckel > const &) const
Definition coulomb.cpp:107
auto operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:102
auto operator()(std::shared_ptr< CoulombP3M > const &actor) const
Definition coulomb.cpp:133
auto operator()(std::shared_ptr< CoulombMMM1D > const &) const
Definition coulomb.cpp:143
auto operator()(std::shared_ptr< ElectrostaticLayerCorrection > const &actor) const
Definition coulomb.cpp:137
auto operator()(std::shared_ptr< ReactionField > const &actor) const
Definition coulomb.cpp:152
auto operator()(std::shared_ptr< DebyeHueckel > const &actor) const
Definition coulomb.cpp:155
auto operator()(std::shared_ptr< CoulombScafacos > const &actor) const
Definition coulomb.cpp:148
Utils::Vector9d calc_pressure_long_range() const
Definition coulomb.cpp:124
double calc_energy_long_range() const
Definition coulomb.cpp:222
void on_observable_calc()
Definition coulomb.cpp:181
double cutoff() const
Definition coulomb.cpp:160
void sanity_checks() const
Definition coulomb.cpp:61
void on_cell_structure_change()
Definition coulomb.cpp:93
void on_periodicity_change()
Definition coulomb.cpp:86
void calc_long_range_force() const
Definition coulomb.cpp:216
void on_node_grid_change()
Definition coulomb.cpp:80
void on_coulomb_change()
Definition coulomb.cpp:67
std::unique_ptr< Implementation > impl
Pointer-to-implementation.
void on_boxl_change()
Definition coulomb.cpp:74
bool reinit_on_observable_calc
Whether to reinitialize the solver on observable calculation.
The electrostatic method supports pressure calculation.
Definition coulomb.hpp:76
void visit_try_catch(Visitor &&visitor, Variant &actor)
Run a kernel on a variant and queue errors.