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