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
22#include <config/config.hpp>
23
24#include "BoxGeometry.hpp"
25#include "Particle.hpp"
26#include "PropagationMode.hpp"
29#include "cells.hpp"
30#include "collision_detection/CollisionDetection.hpp"
31#include "communication.hpp"
32#include "constraints/Constraints.hpp"
34#include "forces_inline.hpp"
35#include "galilei/ComFixed.hpp"
42#include "npt.hpp"
43#include "rotation.hpp"
45#include "short_range_loop.hpp"
46#include "system/System.hpp"
47#include "thermostat.hpp"
49#include "virtual_sites/com.hpp"
51
52#include <utils/Vector.hpp>
53#include <utils/math/sqr.hpp>
54
55#ifdef ESPRESSO_CALIPER
56#include <caliper/cali.h>
57#endif
58
59#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
60#include <Cabana_Core.hpp>
61#endif
62
63#include <cassert>
64#include <cmath>
65#include <memory>
66#include <span>
67#include <variant>
68
69/** External particle forces */
71 ParticleForce f = {};
72
73#ifdef ESPRESSO_EXTERNAL_FORCES
74 f.f += p.ext_force();
75#ifdef ESPRESSO_ROTATION
76 f.torque += p.ext_torque();
77#endif
78#endif
79
80#ifdef ESPRESSO_ENGINE
81 // apply a swimming force in the direction of
82 // the particle's orientation axis
83 if (p.swimming().swimming and !p.swimming().is_engine_force_on_fluid) {
84 f.f += p.swimming().f_swim * p.calc_director();
85 }
86#endif
87
88 return f;
89}
90
91/** Combined force initialization and Langevin noise application */
92static void init_forces_and_thermostat(System::System const &system) {
93#ifdef ESPRESSO_CALIPER
94 CALI_CXX_MARK_FUNCTION;
95#endif
96
97 auto &cell_structure = *system.cell_structure;
98 auto const &propagation = *system.propagation;
99 auto const &thermostat = *system.thermostat;
100 auto const kT = thermostat.kT;
101 auto const time_step = system.get_time_step();
102
103 // Check if Langevin thermostat is active
104 bool const langevin_active =
105 thermostat.langevin &&
106 (propagation.used_propagations &
108
109 // Single pass over all local particles
110 cell_structure.for_each_local_particle([&](Particle &p) {
111 // Initialize force with external forces
113
114 // Apply Langevin noise if thermostat is active
115 if (langevin_active) {
116 auto const &langevin = *thermostat.langevin;
117 if (propagation.should_propagate_with(p, PropagationMode::TRANS_LANGEVIN))
118 p.force() += friction_thermo_langevin(langevin, p, time_step, kT);
119#ifdef ESPRESSO_ROTATION
120 if (propagation.should_propagate_with(p, PropagationMode::ROT_LANGEVIN))
122 p, friction_thermo_langevin_rotation(langevin, p, time_step, kT));
123#endif
124 }
125 });
126#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
127 cell_structure.reset_local_force();
128#endif
129
130 // Initialize ghost forces (unchanged)
131 cell_structure.ghosts_reset_forces();
132}
133
134static void force_capping(CellStructure &cell_structure, double force_cap) {
135 if (force_cap > 0.) {
136 auto const force_cap_sq = Utils::sqr(force_cap);
137 cell_structure.for_each_local_particle(
138 [&force_cap, &force_cap_sq](Particle &p) {
139 auto const force_sq = p.force().norm2();
140 if (force_sq > force_cap_sq) {
141 p.force() *= force_cap / std::sqrt(force_sq);
142 }
143 });
144 }
145}
146
147#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
148static void reinit_dip_fld(CellStructure const &cell_structure) {
149 cell_structure.for_each_local_particle(
150 [](Particle &p) { p.dip_fld() = {0., 0., 0.}; });
151}
152#endif
153
154#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
156 System::System const &system, Utils::Vector3d *virial,
157 auto const &elc_kernel, auto const &coulomb_kernel,
158 auto const &dipoles_kernel, auto const &coulomb_u_kernel) {
159
160 auto const &unique_particles = system.cell_structure->get_unique_particles();
161 auto const &local_force = system.cell_structure->get_local_force();
162#ifdef ESPRESSO_ROTATION
163 auto const &local_torque = system.cell_structure->get_local_torque();
164#endif
165#ifdef ESPRESSO_NPT
166 auto const &local_virial = system.cell_structure->get_local_virial();
167#endif
168 auto const &aosoa = system.cell_structure->get_aosoa();
169
170 return /* ForcesKernel */ {*system.bonded_ias,
171 *system.nonbonded_ias,
172 get_ptr(coulomb_kernel),
173 get_ptr(dipoles_kernel),
174 get_ptr(elc_kernel),
175 get_ptr(coulomb_u_kernel),
176 system.coulomb,
177 *system.thermostat,
178 *system.box_geo,
179 unique_particles,
180 local_force,
181#ifdef ESPRESSO_ROTATION
182 local_torque,
183#endif
184#ifdef ESPRESSO_NPT
185 virial,
186 local_virial,
187#endif
188 aosoa};
189}
190
192 Utils::Vector3d *virial) {
193 auto const &unique_particles = system.cell_structure->get_unique_particles();
194 auto const &local_force = system.cell_structure->get_local_force();
195#ifdef ESPRESSO_ROTATION
196 auto const &local_torque = system.cell_structure->get_local_torque();
197#endif
198#ifdef ESPRESSO_NPT
199 auto const &local_virial = system.cell_structure->get_local_virial();
200#endif
201
202 using execution_space = Kokkos::DefaultExecutionSpace;
203 int num_threads = execution_space().concurrency();
204 Kokkos::RangePolicy<execution_space> policy(std::size_t{0},
205 unique_particles.size());
206 Kokkos::parallel_for("reduction", policy,
207 [&local_force,
208#ifdef ESPRESSO_ROTATION
209 &local_torque,
210#endif
211 &unique_particles, num_threads](std::size_t const i) {
212 Utils::Vector3d force{};
213#ifdef ESPRESSO_ROTATION
214 Utils::Vector3d torque{};
215#endif
216 for (int tid = 0; tid < num_threads; ++tid) {
217 force[0] += local_force(i, tid, 0);
218 force[1] += local_force(i, tid, 1);
219 force[2] += local_force(i, tid, 2);
220#ifdef ESPRESSO_ROTATION
221 torque[0] += local_torque(i, tid, 0);
222 torque[1] += local_torque(i, tid, 1);
223 torque[2] += local_torque(i, tid, 2);
224#endif
225 }
226 unique_particles.at(i)->force() += force;
227#ifdef ESPRESSO_ROTATION
228 unique_particles.at(i)->torque() += torque;
229#endif
230 });
231 Kokkos::fence();
232
233#ifdef ESPRESSO_NPT
234 if (virial) {
235 for (int tid = 0; tid < num_threads; ++tid) {
236 (*virial)[0] += local_virial(tid, 0);
237 (*virial)[1] += local_virial(tid, 1);
238 (*virial)[2] += local_virial(tid, 2);
239 }
240 }
241#endif
242}
243#endif // ESPRESSO_SHARED_MEMORY_PARALLELISM
244
246#ifdef ESPRESSO_CALIPER
247 CALI_CXX_MARK_FUNCTION;
248#endif
249#ifdef ESPRESSO_CUDA
250 {
251#ifdef ESPRESSO_CALIPER
252 CALI_MARK_BEGIN("copy_particles_to_GPU");
253#endif
254 gpu.update();
255#ifdef ESPRESSO_CALIPER
256 CALI_MARK_END("copy_particles_to_GPU");
257#endif
258 }
259#endif // ESPRESSO_CUDA
260
261#ifdef ESPRESSO_COLLISION_DETECTION
262 collision_detection->clear_queue();
263 auto const collision_detection_cutoff = collision_detection->cutoff();
264#else
265 auto const collision_detection_cutoff = inactive_cutoff;
266#endif
267 bond_breakage->clear_queue();
268 auto particles = cell_structure->local_particles();
269#ifdef ESPRESSO_NPT
270 if (propagation->used_propagations & PropagationMode::TRANS_LANGEVIN_NPT) {
271 // reset virial part of instantaneous pressure
272 npt_inst_pressure->p_vir = Utils::Vector3d{};
273 }
274#endif
275#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
276 // reset dipole field
277 reinit_dip_fld(*cell_structure);
278#endif
279
280 // Use combined function instead of two separate calls
281
282 auto const elc_kernel = coulomb.pair_force_elc_kernel();
283 auto const coulomb_kernel = coulomb.pair_force_kernel();
284 auto const dipoles_kernel = dipoles.pair_force_kernel();
285 auto const coulomb_u_kernel = coulomb.pair_energy_kernel();
286 auto *const virial = get_npt_virial();
287
288 // interaction kernel is defined
289 auto bond_kernel = [coulomb_kernel_ptr = get_ptr(coulomb_kernel),
290 &bonded_ias = *bonded_ias,
291 &bond_breakage = *bond_breakage, virial,
292 &box_geo = *box_geo](Particle &p1, int bond_id,
293 std::span<Particle *> partners) {
294 return add_bonded_force(p1, bond_id, partners, bonded_ias, bond_breakage,
295 box_geo, virial, coulomb_kernel_ptr);
296 };
297
298 VerletCriterion<> const verlet_criterion{*this,
299 cell_structure->get_verlet_skin(),
300 get_interaction_range(),
301 coulomb.cutoff(),
302 dipoles.cutoff(),
303 collision_detection_cutoff};
304
305#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
306 update_cabana_state(*cell_structure, verlet_criterion,
307 get_interaction_range(), propagation->integ_switch);
308#endif
309#ifdef ESPRESSO_ELECTROSTATICS
310 if (coulomb.impl->extension) {
311 update_icc_particles();
312 }
313#endif // ESPRESSO_ELECTROSTATICS
315#ifdef ESPRESSO_CALIPER
316 CALI_MARK_BEGIN("calc_long_range_forces");
317#endif
318#ifdef ESPRESSO_ELECTROSTATICS
319 coulomb.calc_long_range_force();
320#endif
321#ifdef ESPRESSO_DIPOLES
322 dipoles.calc_long_range_force();
323#endif
324#ifdef ESPRESSO_CALIPER
325 CALI_MARK_END("calc_long_range_forces");
326#endif
327
328#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
329#ifdef ESPRESSO_CALIPER
330 CALI_MARK_BEGIN("cabana_short_range");
331#endif
332
333 auto first_neighbor_kernel =
334 create_cabana_neighbor_kernel(*this, virial, elc_kernel, coulomb_kernel,
335 dipoles_kernel, coulomb_u_kernel);
336
337 cabana_short_range(bond_kernel, first_neighbor_kernel, *cell_structure,
338 get_interaction_range(), bonded_ias->maximal_cutoff(),
339 verlet_criterion, propagation->integ_switch);
340
341 // Force and Torque reduction
343
344#ifdef ESPRESSO_COLLISION_DETECTION
345 auto collision_kernel = [&collision_detection = *collision_detection](
346 Particle const &p1, Particle const &p2,
347 Distance const &d) {
348 collision_detection.detect_collision(p1, p2, d.dist2);
349 };
350 if (not collision_detection->is_off()) {
351 cell_structure->non_bonded_loop(collision_kernel, verlet_criterion);
352 }
353#endif
354
355#ifdef ESPRESSO_CALIPER
356 CALI_MARK_END("cabana_short_range");
357#endif
358
359#else // ESPRESSO_SHARED_MEMORY_PARALLELISM
360
361#ifdef ESPRESSO_CALIPER
362 CALI_MARK_BEGIN("serial_short_range");
363#endif
364
365 auto pair_kernel = [coulomb_kernel_ptr = get_ptr(coulomb_kernel),
366 dipoles_kernel_ptr = get_ptr(dipoles_kernel),
367 elc_kernel_ptr = get_ptr(elc_kernel),
368 coulomb_u_kernel_ptr = get_ptr(coulomb_u_kernel),
369 &nonbonded_ias = *nonbonded_ias,
370 &thermostat = *thermostat, &bonded_ias = *bonded_ias,
371 virial,
372#ifdef ESPRESSO_COLLISION_DETECTION
373 &collision_detection = *collision_detection,
374#endif
375 &box_geo = *box_geo](Particle &p1, Particle &p2,
376 Distance const &d) {
377 auto const &ia_params = nonbonded_ias.get_ia_param(p1.type(), p2.type());
379 p1, p2, d.vec21, sqrt(d.dist2), d.dist2, p1.q() * p2.q(), ia_params,
380 thermostat, box_geo, bonded_ias, virial, coulomb_kernel_ptr,
381 dipoles_kernel_ptr, elc_kernel_ptr, coulomb_u_kernel_ptr);
382#ifdef ESPRESSO_COLLISION_DETECTION
383 if (not collision_detection.is_off()) {
384 collision_detection.detect_collision(p1, p2, d.dist2);
385 }
386#endif
387 };
388
389 short_range_loop(bond_kernel, pair_kernel, *cell_structure, maximal_cutoff(),
390 bonded_ias->maximal_cutoff(), verlet_criterion);
391
392#ifdef ESPRESSO_CALIPER
393 CALI_MARK_END("serial_short_range");
394#endif
395
396#endif // ESPRESSO_SHARED_MEMORY_PARALLELISM
397
398 constraints->add_forces(particles, get_sim_time());
399 oif_global->calculate_forces();
400
401 // Must be done here. Forces need to be ghost-communicated
402 immersed_boundaries->volume_conservation(*cell_structure);
403
404 if (thermostat->lb and (propagation->used_propagations &
406#ifdef ESPRESSO_CALIPER
407 CALI_MARK_BEGIN("lb_particle_coupling");
408#endif
409 lb_couple_particles();
410#ifdef ESPRESSO_CALIPER
411 CALI_MARK_END("lb_particle_coupling");
412#endif
413 }
414
415#ifdef ESPRESSO_CUDA
416 {
417#ifdef ESPRESSO_CALIPER
418 CALI_MARK_BEGIN("copy_forces_from_GPU");
419#endif
420 gpu.copy_forces_to_host(particles, this_node);
421
422#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
423 gpu.copy_dip_fld_to_host(particles, this_node);
424#endif
425
426#ifdef ESPRESSO_CALIPER
427 CALI_MARK_END("copy_forces_from_GPU");
428#endif
429 }
430#endif // ESPRESSO_CUDA
431
432#ifdef ESPRESSO_VIRTUAL_SITES_RELATIVE
433 if (propagation->used_propagations &
437 }
438#endif
439#ifdef ESPRESSO_VIRTUAL_SITES_CENTER_OF_MASS
440 if (propagation->used_propagations &
443 }
444#endif
445
446 // Communication step: ghost forces
447 cell_structure->ghosts_reduce_forces();
448
449 // should be pretty late, since it needs to zero out the total force
450 comfixed->apply(particles);
451
452 // Needs to be the last one to be effective
453 force_capping(*cell_structure, force_cap);
454
455 // mark that forces are now up-to-date
456 propagation->recalc_forces = false;
457}
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.
Main system class.
auto get_time_step() const
Get time_step.
std::shared_ptr< BondedInteractionsMap > bonded_ias
void calculate_forces()
Calculate all forces.
Definition forces.cpp:245
std::shared_ptr< Propagation > propagation
std::shared_ptr< Thermostat::Thermostat > thermostat
std::shared_ptr< CellStructure > cell_structure
Coulomb::Solver coulomb
std::shared_ptr< BoxGeometry > box_geo
std::shared_ptr< InteractionsNonBonded > nonbonded_ias
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:204
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:148
static void force_capping(CellStructure &cell_structure, double force_cap)
Definition forces.cpp:134
static void init_forces_and_thermostat(System::System const &system)
Combined force initialization and Langevin noise application.
Definition forces.cpp:92
static ParticleForce external_force(Particle const &p)
External particle forces.
Definition forces.cpp:70
static ForcesKernel create_cabana_neighbor_kernel(System::System const &system, Utils::Vector3d *virial, auto const &elc_kernel, auto const &coulomb_kernel, auto const &dipoles_kernel, auto const &coulomb_u_kernel)
Definition forces.cpp:155
static void reduce_cabana_forces_and_torques(System::System const &system, Utils::Vector3d *virial)
Definition forces.cpp:191
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.
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:163
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={})
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