ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
forces.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/** \file
22 * Force calculation.
23 *
24 * The corresponding header file is forces.hpp.
25 */
26
27#include <config/config.hpp>
28
29#include "BoxGeometry.hpp"
30#include "Particle.hpp"
31#include "ParticleRange.hpp"
32#include "PropagationMode.hpp"
35#include "cells.hpp"
36#include "collision_detection/CollisionDetection.hpp"
37#include "communication.hpp"
38#include "constraints/Constraints.hpp"
40#include "forces_inline.hpp"
41#include "galilei/ComFixed.hpp"
48#include "npt.hpp"
49#include "rotation.hpp"
51#include "short_range_loop.hpp"
52#include "system/System.hpp"
53#include "thermostat.hpp"
55#include "virtual_sites/com.hpp"
57
58#include <utils/Vector.hpp>
59#include <utils/math/sqr.hpp>
60
61#ifdef ESPRESSO_CALIPER
62#include <caliper/cali.h>
63#endif
64
65#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
66#include <Cabana_Core.hpp>
67#endif
68
69#include <cassert>
70#include <cmath>
71#include <memory>
72#include <span>
73#include <variant>
74
75/** External particle forces */
77 ParticleForce f = {};
78
79#ifdef ESPRESSO_EXTERNAL_FORCES
80 f.f += p.ext_force();
81#ifdef ESPRESSO_ROTATION
82 f.torque += p.ext_torque();
83#endif
84#endif
85
86#ifdef ESPRESSO_ENGINE
87 // apply a swimming force in the direction of
88 // the particle's orientation axis
89 if (p.swimming().swimming and !p.swimming().is_engine_force_on_fluid) {
90 f.f += p.swimming().f_swim * p.calc_director();
91 }
92#endif
93
94 return f;
95}
96
97/** Combined force initialization and Langevin noise application */
99#ifdef ESPRESSO_CALIPER
100 CALI_CXX_MARK_FUNCTION;
101#endif
102
103 auto &cell_structure = *system.cell_structure;
104 auto const &propagation = *system.propagation;
105 auto const &thermostat = *system.thermostat;
106 auto const kT = thermostat.kT;
107 auto const time_step = system.get_time_step();
108
109 // Check if Langevin thermostat is active
110 bool const langevin_active =
111 thermostat.langevin &&
112 (propagation.used_propagations &
114
115 // Single pass over all local particles
116 cell_structure.for_each_local_particle([&](Particle &p) {
117 // Initialize force with external forces
119
120 // Apply Langevin noise if thermostat is active
121 if (langevin_active) {
122 auto const &langevin = *thermostat.langevin;
123 if (propagation.should_propagate_with(p, PropagationMode::TRANS_LANGEVIN))
124 p.force() += friction_thermo_langevin(langevin, p, time_step, kT);
125#ifdef ESPRESSO_ROTATION
126 if (propagation.should_propagate_with(p, PropagationMode::ROT_LANGEVIN))
128 p, friction_thermo_langevin_rotation(langevin, p, time_step, kT));
129#endif
130 }
131 });
132#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
133 cell_structure.reset_local_force();
134#endif
135
136 // Initialize ghost forces (unchanged)
137 init_forces_ghosts(cell_structure);
138}
139
140void init_forces_ghosts(const CellStructure &cell_structure) {
141 cell_structure.for_each_ghost_particle(
142 [](Particle &p) { p.force_and_torque() = {}; });
143}
144
145static void force_capping(CellStructure &cell_structure, double force_cap) {
146 if (force_cap > 0.) {
147 auto const force_cap_sq = Utils::sqr(force_cap);
148 cell_structure.for_each_local_particle(
149 [&force_cap, &force_cap_sq](Particle &p) {
150 auto const force_sq = p.force().norm2();
151 if (force_sq > force_cap_sq) {
152 p.force() *= force_cap / std::sqrt(force_sq);
153 }
154 });
155 }
156}
157
158#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
159static void reinit_dip_fld(CellStructure const &cell_structure) {
160 cell_structure.for_each_local_particle(
161 [](Particle &p) { p.dip_fld() = {0., 0., 0.}; });
162}
163#endif
164
166#ifdef ESPRESSO_CALIPER
167 CALI_CXX_MARK_FUNCTION;
168#endif
169#ifdef ESPRESSO_CUDA
170 {
171#ifdef ESPRESSO_CALIPER
172 CALI_MARK_BEGIN("copy_particles_to_GPU");
173#endif
174 gpu.update();
175#ifdef ESPRESSO_CALIPER
176 CALI_MARK_END("copy_particles_to_GPU");
177#endif
178 }
179#endif // ESPRESSO_CUDA
180
181#ifdef ESPRESSO_COLLISION_DETECTION
182 collision_detection->clear_queue();
183 auto const collision_detection_cutoff = collision_detection->cutoff();
184#else
185 auto const collision_detection_cutoff = inactive_cutoff;
186#endif
187 bond_breakage->clear_queue();
188 auto particles = cell_structure->local_particles();
189#ifdef ESPRESSO_NPT
190 if (propagation->used_propagations & PropagationMode::TRANS_LANGEVIN_NPT) {
191 // reset virial part of instantaneous pressure
192 npt_inst_pressure->p_vir = Utils::Vector3d{};
193 }
194#endif
195#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
196 // reset dipole field
197 reinit_dip_fld(*cell_structure);
198#endif
199
200 // Use combined function instead of two separate calls
201
202 auto const elc_kernel = coulomb.pair_force_elc_kernel();
203 auto const coulomb_kernel = coulomb.pair_force_kernel();
204 auto const dipoles_kernel = dipoles.pair_force_kernel();
205 auto const coulomb_u_kernel = coulomb.pair_energy_kernel();
206 auto *const virial = get_npt_virial();
207
208 // interaction kernel is defined
209 auto bond_kernel = [coulomb_kernel_ptr = get_ptr(coulomb_kernel),
210 &bonded_ias = *bonded_ias,
211 &bond_breakage = *bond_breakage, virial,
212 &box_geo = *box_geo](Particle &p1, int bond_id,
213 std::span<Particle *> partners) {
214 return add_bonded_force(p1, bond_id, partners, bonded_ias, bond_breakage,
215 box_geo, virial, coulomb_kernel_ptr);
216 };
217
218 VerletCriterion<> const verlet_criterion{*this,
219 cell_structure->get_verlet_skin(),
220 get_interaction_range(),
221 coulomb.cutoff(),
222 dipoles.cutoff(),
223 collision_detection_cutoff};
224
225#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
226 update_cabana_state(*cell_structure, verlet_criterion,
227 get_interaction_range(), propagation->integ_switch);
228#endif
229#ifdef ESPRESSO_ELECTROSTATICS
230 if (coulomb.impl->extension) {
231 update_icc_particles();
232 }
233#endif // ESPRESSO_ELECTROSTATICS
235 calc_long_range_forces(particles);
236
237#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
238#ifdef ESPRESSO_CALIPER
239 CALI_MARK_BEGIN("cabana_short_range");
240#endif
241 using execution_space = Kokkos::DefaultExecutionSpace;
242 auto const &unique_particles = cell_structure->get_unique_particles();
243 auto const &local_force = cell_structure->get_local_force();
244#ifdef ESPRESSO_ROTATION
245 auto const &local_torque = cell_structure->get_local_torque();
246#endif
247#ifdef ESPRESSO_NPT
248 auto const &local_virial = cell_structure->get_local_virial();
249#endif
250 auto const &aosoa = cell_structure->get_aosoa();
251
252 ForcesKernel first_neighbor_kernel(
253 *bonded_ias, *nonbonded_ias, get_ptr(coulomb_kernel),
254 get_ptr(dipoles_kernel), get_ptr(elc_kernel), get_ptr(coulomb_u_kernel),
255 *thermostat, *box_geo, unique_particles, local_force,
256#ifdef ESPRESSO_ROTATION
257 local_torque,
258#endif
259#ifdef ESPRESSO_NPT
260 virial, local_virial,
261#endif
262 aosoa);
263
264 cabana_short_range(bond_kernel, first_neighbor_kernel, *cell_structure,
265 get_interaction_range(), bonded_ias->maximal_cutoff(),
266 verlet_criterion, propagation->integ_switch);
267 // Force and Torque reduction
268 int num_threads = execution_space().concurrency();
269 Kokkos::RangePolicy<execution_space> policy(std::size_t{0},
270 unique_particles.size());
271 Kokkos::parallel_for("reduction", policy,
272 [&local_force,
273#ifdef ESPRESSO_ROTATION
274 &local_torque,
275#endif
276 &unique_particles, num_threads](std::size_t const i) {
277 Utils::Vector3d force{};
278#ifdef ESPRESSO_ROTATION
279 Utils::Vector3d torque{};
280#endif
281 for (int tid = 0; tid < num_threads; ++tid) {
282 force[0] += local_force(i, tid, 0);
283 force[1] += local_force(i, tid, 1);
284 force[2] += local_force(i, tid, 2);
285#ifdef ESPRESSO_ROTATION
286 torque[0] += local_torque(i, tid, 0);
287 torque[1] += local_torque(i, tid, 1);
288 torque[2] += local_torque(i, tid, 2);
289#endif
290 }
291 unique_particles.at(i)->force() += force;
292#ifdef ESPRESSO_ROTATION
293 unique_particles.at(i)->torque() += torque;
294#endif
295 });
296 Kokkos::fence();
297
298#ifdef ESPRESSO_NPT
299 if (virial) {
300 for (int tid = 0; tid < num_threads; ++tid) {
301 (*virial)[0] += local_virial(tid, 0);
302 (*virial)[1] += local_virial(tid, 1);
303 (*virial)[2] += local_virial(tid, 2);
304 }
305 }
306#endif
307
308#ifdef ESPRESSO_COLLISION_DETECTION
309 auto collision_kernel = [&collision_detection = *collision_detection](
310 Particle const &p1, Particle const &p2,
311 Distance const &d) {
312 collision_detection.detect_collision(p1, p2, d.dist2);
313 };
314 if (not collision_detection->is_off()) {
315 cell_structure->non_bonded_loop(collision_kernel, verlet_criterion);
316 }
317#endif
318
319#ifdef ESPRESSO_CALIPER
320 CALI_MARK_END("cabana_short_range");
321#endif
322
323#else // ESPRESSO_SHARED_MEMORY_PARALLELISM
324
325#ifdef ESPRESSO_CALIPER
326 CALI_MARK_BEGIN("serial_short_range");
327#endif
328
329 auto pair_kernel = [coulomb_kernel_ptr = get_ptr(coulomb_kernel),
330 dipoles_kernel_ptr = get_ptr(dipoles_kernel),
331 elc_kernel_ptr = get_ptr(elc_kernel),
332 coulomb_u_kernel_ptr = get_ptr(coulomb_u_kernel),
333 &nonbonded_ias = *nonbonded_ias,
334 &thermostat = *thermostat, &bonded_ias = *bonded_ias,
335 virial,
336#ifdef ESPRESSO_COLLISION_DETECTION
337 &collision_detection = *collision_detection,
338#endif
339 &box_geo = *box_geo](Particle &p1, Particle &p2,
340 Distance const &d) {
341 auto const &ia_params = nonbonded_ias.get_ia_param(p1.type(), p2.type());
343 p1, p2, d.vec21, sqrt(d.dist2), d.dist2, p1.q() * p2.q(), ia_params,
344 thermostat, box_geo, bonded_ias, virial, coulomb_kernel_ptr,
345 dipoles_kernel_ptr, elc_kernel_ptr, coulomb_u_kernel_ptr);
346#ifdef ESPRESSO_COLLISION_DETECTION
347 if (not collision_detection.is_off()) {
348 collision_detection.detect_collision(p1, p2, d.dist2);
349 }
350#endif
351 };
352
353 short_range_loop(bond_kernel, pair_kernel, *cell_structure, maximal_cutoff(),
354 bonded_ias->maximal_cutoff(), verlet_criterion);
355
356#ifdef ESPRESSO_CALIPER
357 CALI_MARK_END("serial_short_range");
358#endif
359
360#endif // ESPRESSO_SHARED_MEMORY_PARALLELISM
361
362 constraints->add_forces(particles, get_sim_time());
363 oif_global->calculate_forces();
364
365 // Must be done here. Forces need to be ghost-communicated
366 immersed_boundaries->volume_conservation(*cell_structure);
367
368 if (thermostat->lb and (propagation->used_propagations &
370#ifdef ESPRESSO_CALIPER
371 CALI_MARK_BEGIN("lb_particle_coupling");
372#endif
373 lb_couple_particles();
374#ifdef ESPRESSO_CALIPER
375 CALI_MARK_END("lb_particle_coupling");
376#endif
377 }
378
379#ifdef ESPRESSO_CUDA
380 {
381#ifdef ESPRESSO_CALIPER
382 CALI_MARK_BEGIN("copy_forces_from_GPU");
383#endif
384 gpu.copy_forces_to_host(particles, this_node);
385
386#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
387 gpu.copy_dip_fld_to_host(particles, this_node);
388#endif
389
390#ifdef ESPRESSO_CALIPER
391 CALI_MARK_END("copy_forces_from_GPU");
392#endif
393 }
394#endif // ESPRESSO_CUDA
395
396#ifdef ESPRESSO_VIRTUAL_SITES_RELATIVE
397 if (propagation->used_propagations &
401 }
402#endif
403#ifdef ESPRESSO_VIRTUAL_SITES_CENTER_OF_MASS
404 if (propagation->used_propagations &
407 }
408#endif
409
410 // Communication step: ghost forces
411 cell_structure->ghosts_reduce_forces();
412
413 // should be pretty late, since it needs to zero out the total force
414 comfixed->apply(particles);
415
416 // Needs to be the last one to be effective
417 force_capping(*cell_structure, force_cap);
418
419 // mark that forces are now up-to-date
420 propagation->recalc_forces = false;
421}
422
423void calc_long_range_forces(const ParticleRange &particles) {
424#ifdef ESPRESSO_CALIPER
425 CALI_CXX_MARK_FUNCTION;
426#endif
427
428#ifdef ESPRESSO_ELECTROSTATICS
429 /* calculate k-space part of electrostatic interaction. */
431#endif // ESPRESSO_ELECTROSTATICS
432
433#ifdef ESPRESSO_DIPOLES
434 /* calculate k-space part of the magnetostatic interaction. */
436#endif // ESPRESSO_DIPOLES
437}
Vector implementation and trait types for boost qvm interoperability.
This file contains everything related to the global cell structure / cell system.
Describes a cell structure / cell system.
void for_each_local_particle(ParticleUnaryOp &&f, bool parallel=true) const
Run a kernel on all local particles.
void for_each_ghost_particle(ParticleUnaryOp &&f) const
Run a kernel on all ghost particles.
A range of particles.
Main system class.
auto get_time_step() const
Get time_step.
void calculate_forces()
Calculate all forces.
Definition forces.cpp:165
std::shared_ptr< Propagation > propagation
std::shared_ptr< Thermostat::Thermostat > thermostat
std::shared_ptr< CellStructure > cell_structure
Returns true if the particles are to be considered for short range interactions.
void vs_com_back_transfer_forces_and_torques(CellStructure &cell_structure)
Definition com.cpp:209
int this_node
The number of this node.
constexpr double inactive_cutoff
Special cutoff value for an inactive interaction.
Definition config.hpp:44
const T * get_ptr(std::optional< T > const &opt)
static void reinit_dip_fld(CellStructure const &cell_structure)
Definition forces.cpp:159
static void force_capping(CellStructure &cell_structure, double force_cap)
Definition forces.cpp:145
void init_forces_ghosts(const CellStructure &cell_structure)
Set forces of all ghosts to zero.
Definition forces.cpp:140
static ParticleForce external_force(Particle const &p)
External particle forces.
Definition forces.cpp:76
void init_forces_and_thermostat(System::System const &system)
Combined force initialization and Langevin noise application.
Definition forces.cpp:98
void calc_long_range_forces(const ParticleRange &particles)
Calculate long range forces (P3M, ...).
Definition forces.cpp:423
Force calculation.
void add_non_bonded_pair_force(Particle &p1, Particle &p2, Utils::Vector3d const &d, double dist, double dist2, double q1q2, IA_parameters const &ia_params, Thermostat::Thermostat const &thermostat, BoxGeometry const &box_geo, BondedInteractionsMap const &bonded_ias, Utils::Vector3d *const virial, Coulomb::ShortRangeForceKernel::kernel_type const *coulomb_kernel, Dipoles::ShortRangeForceKernel::kernel_type const *dipoles_kernel, Coulomb::ShortRangeForceCorrectionsKernel::kernel_type const *elc_kernel, Coulomb::ShortRangeEnergyKernel::kernel_type const *coulomb_u_kernel)
Calculate non-bonded forces between a pair of particles and update their forces and torques.
bool add_bonded_force(Particle &p1, int bond_id, std::span< Particle * > partners, BondedInteractionsMap const &bonded_ia_params, BondBreakage::BondBreakage &bond_breakage, BoxGeometry const &box_geo, Utils::Vector3d *const virial, Coulomb::ShortRangeForceKernel::kernel_type const *kernel)
ICC is a method that allows to take into account the influence of arbitrarily shaped dielectric inter...
Utils::Vector3d friction_thermo_langevin(LangevinThermostat const &langevin, Particle const &p, double time_step, double kT)
Langevin thermostat for particle translational velocities.
Utils::Vector3d friction_thermo_langevin_rotation(LangevinThermostat const &langevin, Particle const &p, double time_step, double kT)
Langevin thermostat for particle angular velocities.
Solver const & get_coulomb()
Definition coulomb.cpp:65
Solver const & get_dipoles()
Definition dipoles.cpp:49
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
Various procedures concerning interactions between particles.
Exports for the NpT code.
void vs_relative_back_transfer_forces_and_torques(CellStructure &cell_structure)
Definition relative.cpp:164
This file contains all subroutines required to process rotational motion.
Utils::Vector3d convert_vector_body_to_space(const Particle &p, const Utils::Vector3d &vec)
Definition rotation.hpp:58
ESPRESSO_ATTR_ALWAYS_INLINE void update_cabana_state(CellStructure &cell_structure, auto const &verlet_criterion, double const pair_cutoff, auto const integ_switch)
void cabana_short_range(auto const &bond_kernel, auto const &forces_kernel, CellStructure &cell_structure, double pair_cutoff, double bond_cutoff, auto const &verlet_criterion, auto const integ_switch)
void short_range_loop(BondKernel bond_kernel, PairKernel pair_kernel, CellStructure &cell_structure, double pair_cutoff, double bond_cutoff, VerletCriterion const &verlet_criterion={})
void calc_long_range_force(ParticleRange const &particles) const
Definition coulomb.cpp:261
void calc_long_range_force(ParticleRange const &particles) const
Definition dipoles.cpp:180
Distance vector and length handed to pair kernels.
Force information on a particle.
Definition Particle.hpp:345
Utils::Vector3d torque
torque.
Definition Particle.hpp:375
Utils::Vector3d f
force.
Definition Particle.hpp:371
Struct holding all information for one particle.
Definition Particle.hpp:450
auto const & dip_fld() const
Definition Particle.hpp:583
auto const & swimming() const
Definition Particle.hpp:652
auto const & force_and_torque() const
Definition Particle.hpp:492
auto const & torque() const
Definition Particle.hpp:534
auto const & ext_force() const
Definition Particle.hpp:645
auto const & ext_torque() const
Definition Particle.hpp:539
auto const & force() const
Definition Particle.hpp:490
auto calc_director() const
Definition Particle.hpp:542