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-2026 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"
47#include "system/System.hpp"
48#include "thermostat.hpp"
50#include "virtual_sites/com.hpp"
52
53#include <utils/Vector.hpp>
54#include <utils/math/sqr.hpp>
55
56#ifdef ESPRESSO_CALIPER
57#include <caliper/cali.h>
58#endif
59
60#include <Cabana_Core.hpp>
61
62#include <cassert>
63#include <cmath>
64#include <cstddef>
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 cell_structure.reset_local_force();
127
128 // Initialize ghost forces (unchanged)
129 cell_structure.ghosts_reset_forces();
130}
131
132static void force_capping(CellStructure &cell_structure, double force_cap) {
133 if (force_cap > 0.) {
134 auto const force_cap_sq = Utils::sqr(force_cap);
135 cell_structure.for_each_local_particle(
136 [&force_cap, &force_cap_sq](Particle &p) {
137 auto const force_sq = p.force().norm2();
138 if (force_sq > force_cap_sq) {
139 p.force() *= force_cap / std::sqrt(force_sq);
140 }
141 });
142 }
143}
144
145#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
146static void reinit_dip_fld(CellStructure const &cell_structure) {
147 cell_structure.for_each_local_particle(
148 [](Particle &p) { p.dip_fld() = {0., 0., 0.}; });
149}
150#endif
151
152static BondsKernelData
154
155 auto &local_force = system.cell_structure->get_local_force();
156#ifdef ESPRESSO_NPT
157 auto &local_virial = system.cell_structure->get_local_virial();
158#endif
159 auto const &aosoa = system.cell_structure->get_aosoa();
160 return /* BondsKernelData */ {*system.bonded_ias,
161 *system.bond_breakage,
162 *system.box_geo,
163 local_force,
164#ifdef ESPRESSO_NPT
165 local_virial,
166#endif
167 aosoa,
168 !system.bond_breakage->breakage_specs.empty()};
169}
170
172 System::System const &system, Utils::Vector3d *virial,
173 auto const &elc_kernel, auto const &coulomb_kernel,
174 auto const &dipoles_kernel, auto const &coulomb_u_kernel) {
175
176 auto const &unique_particles = system.cell_structure->get_unique_particles();
177 auto const &local_force = system.cell_structure->get_local_force();
178#ifdef ESPRESSO_ROTATION
179 auto const &local_torque = system.cell_structure->get_local_torque();
180#endif
181#ifdef ESPRESSO_NPT
182 auto const &local_virial = system.cell_structure->get_local_virial();
183#endif
184 auto const &aosoa = system.cell_structure->get_aosoa();
185
186 return /* ForcesKernel */ {*system.bonded_ias,
187 *system.nonbonded_ias,
188 get_ptr(coulomb_kernel),
189 get_ptr(dipoles_kernel),
190 get_ptr(elc_kernel),
191 get_ptr(coulomb_u_kernel),
192 system.coulomb,
193 *system.thermostat,
194 *system.box_geo,
195 unique_particles,
196 local_force,
197#ifdef ESPRESSO_ROTATION
198 local_torque,
199#endif
200#ifdef ESPRESSO_NPT
201 virial,
202 local_virial,
203#endif
204 aosoa,
205 system.maximal_cutoff()};
206}
207
209 Utils::Vector3d *virial) {
210 auto const &unique_particles = system.cell_structure->get_unique_particles();
211 auto const &local_force = system.cell_structure->get_local_force();
212#ifdef ESPRESSO_ROTATION
213 auto const &local_torque = system.cell_structure->get_local_torque();
214#endif
215#ifdef ESPRESSO_NPT
216 auto const &local_virial = system.cell_structure->get_local_virial();
217#endif
218
219 using execution_space = Kokkos::DefaultExecutionSpace;
220 int num_threads = execution_space().concurrency();
221 Kokkos::RangePolicy<execution_space> policy(std::size_t{0},
222 unique_particles.size());
223 Kokkos::parallel_for("reduction", policy,
224 [&local_force,
225#ifdef ESPRESSO_ROTATION
226 &local_torque,
227#endif
228 &unique_particles, num_threads](std::size_t const i) {
229 Utils::Vector3d force{};
230#ifdef ESPRESSO_ROTATION
231 Utils::Vector3d torque{};
232#endif
233 for (int tid = 0; tid < num_threads; ++tid) {
234 force[0] += local_force(i, tid, 0);
235 force[1] += local_force(i, tid, 1);
236 force[2] += local_force(i, tid, 2);
237#ifdef ESPRESSO_ROTATION
238 torque[0] += local_torque(i, tid, 0);
239 torque[1] += local_torque(i, tid, 1);
240 torque[2] += local_torque(i, tid, 2);
241#endif
242 }
243 unique_particles.at(i)->force() += force;
244#ifdef ESPRESSO_ROTATION
245 unique_particles.at(i)->torque() += torque;
246#endif
247 });
248 Kokkos::fence();
249
250#ifdef ESPRESSO_NPT
251 if (virial) {
252 for (int tid = 0; tid < num_threads; ++tid) {
253 (*virial)[0] += local_virial(tid, 0);
254 (*virial)[1] += local_virial(tid, 1);
255 (*virial)[2] += local_virial(tid, 2);
256 }
257 }
258#endif
259}
260
262#ifdef ESPRESSO_CALIPER
263 CALI_CXX_MARK_FUNCTION;
264#endif
265#ifdef ESPRESSO_CUDA
266 {
267#ifdef ESPRESSO_CALIPER
268 CALI_MARK_BEGIN("copy_particles_to_GPU");
269#endif
270 gpu->update();
271#ifdef ESPRESSO_CALIPER
272 CALI_MARK_END("copy_particles_to_GPU");
273#endif
274 }
275#endif // ESPRESSO_CUDA
276
277#ifdef ESPRESSO_COLLISION_DETECTION
278 collision_detection->clear_queue();
279 auto const collision_detection_cutoff = collision_detection->cutoff();
280#else
281 auto const collision_detection_cutoff = inactive_cutoff;
282#endif
283 bond_breakage->clear_queue();
284 auto particles = cell_structure->local_particles();
285#ifdef ESPRESSO_NPT
286 if (propagation->used_propagations & PropagationMode::TRANS_LANGEVIN_NPT) {
287 // reset virial part of instantaneous pressure
288 npt_inst_pressure->p_vir = Utils::Vector3d{};
289 }
290#endif
291#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
292 // reset dipole field
293 reinit_dip_fld(*cell_structure);
294#endif
295
296 // Use combined function instead of two separate calls
297
298 auto const elc_kernel = coulomb.pair_force_elc_kernel();
299 auto const coulomb_kernel = coulomb.pair_force_kernel();
300 auto const dipoles_kernel = dipoles.pair_force_kernel();
301 auto const coulomb_u_kernel = coulomb.pair_energy_kernel();
302 auto *const virial = get_npt_virial();
303
304 VerletCriterion<> const verlet_criterion{*this,
305 cell_structure->get_verlet_skin(),
306 get_interaction_range(),
307 coulomb.cutoff(),
308 dipoles.cutoff(),
309 collision_detection_cutoff};
310
311 update_cabana_state(*cell_structure, verlet_criterion,
312 get_interaction_range(), propagation->integ_switch);
313#ifdef ESPRESSO_ELECTROSTATICS
314 if (coulomb.impl->extension) {
315 update_icc_particles();
316 }
317#endif // ESPRESSO_ELECTROSTATICS
319#ifdef ESPRESSO_CALIPER
320 CALI_MARK_BEGIN("calc_long_range_forces");
321#endif
322#ifdef ESPRESSO_ELECTROSTATICS
323 coulomb.calc_long_range_force();
324#endif
325#ifdef ESPRESSO_DIPOLES
326 dipoles.calc_long_range_force();
327#endif
328#ifdef ESPRESSO_CALIPER
329 CALI_MARK_END("calc_long_range_forces");
330#endif
331
332#ifdef ESPRESSO_CALIPER
333 CALI_MARK_BEGIN("cabana_short_range");
334#endif
335 auto &bs = cell_structure->bond_state();
336 auto bonds_kernel_data = create_kokkos_bonds_kernel_data(*this);
337 auto pair_bonds_kernel = PairBondsKernel{
338 bonds_kernel_data, bs.pair_list, bs.pair_ids, get_ptr(coulomb_kernel)};
339 auto angle_bonds_kernel =
340 AngleBondsKernel{bonds_kernel_data, bs.angle_list, bs.angle_ids};
341 auto dihedral_bonds_kernel =
342 DihedralBondsKernel{bonds_kernel_data, bs.dihedral_list, bs.dihedral_ids};
343
344 auto first_neighbor_kernel =
345 create_cabana_neighbor_kernel(*this, virial, elc_kernel, coulomb_kernel,
346 dipoles_kernel, coulomb_u_kernel);
347
348 cabana_short_range(pair_bonds_kernel, angle_bonds_kernel,
349 dihedral_bonds_kernel, first_neighbor_kernel,
350 *cell_structure, get_interaction_range(),
351 bonded_ias->maximal_cutoff(), verlet_criterion,
352 propagation->integ_switch);
353
354 // Force and Torque reduction
356
357#ifdef ESPRESSO_COLLISION_DETECTION
358 auto collision_kernel = [&collision_detection = *collision_detection](
359 Particle const &p1, Particle const &p2,
360 Distance const &d) {
361 collision_detection.detect_collision(p1, p2, d.dist2);
362 };
363 if (not collision_detection->is_off()) {
364 cell_structure->non_bonded_loop(collision_kernel, verlet_criterion);
365 }
366#endif // ESPRESSO_COLLISION_DETECTION
367
368#ifdef ESPRESSO_CALIPER
369 CALI_MARK_END("cabana_short_range");
370#endif
371
372 constraints->add_forces(particles, get_sim_time());
373 oif_global->calculate_forces();
374
375 // Must be done here. Forces need to be ghost-communicated
376 immersed_boundaries->volume_conservation(*cell_structure);
377
378 if (thermostat->lb and (propagation->used_propagations &
380#ifdef ESPRESSO_CALIPER
381 CALI_MARK_BEGIN("lb_particle_coupling");
382#endif
383 lb_couple_particles();
384#ifdef ESPRESSO_CALIPER
385 CALI_MARK_END("lb_particle_coupling");
386#endif
387 }
388
389#ifdef ESPRESSO_CUDA
390 {
391#ifdef ESPRESSO_CALIPER
392 CALI_MARK_BEGIN("copy_forces_from_GPU");
393#endif
394 gpu->copy_forces_to_host(particles, this_node);
395
396#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
397 gpu->copy_dip_fld_to_host(particles, this_node);
398#endif
399
400#ifdef ESPRESSO_CALIPER
401 CALI_MARK_END("copy_forces_from_GPU");
402#endif
403 }
404#endif // ESPRESSO_CUDA
405
406#ifdef ESPRESSO_VIRTUAL_SITES_RELATIVE
407 if (propagation->used_propagations &
411 }
412#endif
413#ifdef ESPRESSO_VIRTUAL_SITES_CENTER_OF_MASS
414 if (propagation->used_propagations &
417 }
418#endif
419
420 // Communication step: ghost forces
421 cell_structure->ghosts_reduce_forces();
422
423 // should be pretty late, since it needs to zero out the total force
424 comfixed->apply(particles);
425
426 // Needs to be the last one to be effective
427 force_capping(*cell_structure, force_cap);
428
429 // mark that forces are now up-to-date
430 propagation->recalc_forces = false;
431}
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.
double maximal_cutoff() const
Calculate the maximal cutoff of all interactions.
auto get_time_step() const
Get time_step.
std::shared_ptr< BondedInteractionsMap > bonded_ias
std::shared_ptr< BondBreakage::BondBreakage > bond_breakage
void calculate_forces()
Calculate all forces.
Definition forces.cpp:261
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:231
int this_node
The number of this node.
constexpr double inactive_cutoff
Special cutoff value for an inactive interaction.
Definition config.hpp:53
const T * get_ptr(std::optional< T > const &opt)
static BondsKernelData create_kokkos_bonds_kernel_data(System::System const &system)
Definition forces.cpp:153
static void reinit_dip_fld(CellStructure const &cell_structure)
Definition forces.cpp:146
static void force_capping(CellStructure &cell_structure, double force_cap)
Definition forces.cpp:132
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:171
static void reduce_cabana_forces_and_torques(System::System const &system, Utils::Vector3d *virial)
Definition forces.cpp:208
Force calculation.
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 &pair_bonds_kernel, auto const &angle_bonds_kernel, auto const &dihedral_bonds_kernel, auto const &nonbonded_kernel, CellStructure &cell_structure, double pair_cutoff, double bond_cutoff, auto const &verlet_criterion, auto const integ_switch)
Distance vector and length handed to pair kernels.
Force information on a particle.
Definition Particle.hpp:330
Utils::Vector3d torque
torque.
Definition Particle.hpp:360
Utils::Vector3d f
force.
Definition Particle.hpp:356
Struct holding all information for one particle.
Definition Particle.hpp:435
auto const & dip_fld() const
Definition Particle.hpp:568
auto const & swimming() const
Definition Particle.hpp:633
auto const & force_and_torque() const
Definition Particle.hpp:477
auto const & torque() const
Definition Particle.hpp:519
auto const & ext_force() const
Definition Particle.hpp:626
auto const & ext_torque() const
Definition Particle.hpp:524
auto const & force() const
Definition Particle.hpp:475
auto calc_director() const
Definition Particle.hpp:527