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_init.hpp"
36#include "forces_inline.hpp"
37#include "galilei/ComFixed.hpp"
38#include "ghosts.hpp"
45#include "npt.hpp"
46#include "rotation.hpp"
48#include "short_range_loop.hpp"
51#include "system/System.hpp"
52#include "thermostat.hpp"
53#include "virtual_sites/com.hpp"
55
56#include <utils/Vector.hpp>
57#include <utils/math/sqr.hpp>
58
59#ifdef ESPRESSO_CALIPER
60#include "caliper_utils.hpp"
61#endif
62
63#include <Cabana_Core.hpp>
64
65#include <cassert>
66#include <cmath>
67#include <cstddef>
68#include <memory>
69#include <span>
70#include <variant>
71
72/**
73 * @brief Eligibility check for the split-phase ghost force reduction.
74 *
75 * The overlap is safe only when ALL of the following hold:
76 *
77 * 1. More than one MPI rank: at 1 rank the reduce is a local-only copy,
78 * there is nothing to hide, so the split adds overhead for no gain.
79 * 2. ComFixed is inactive: ComFixed applies a per-type force correction that
80 * must see the final (post-reduce) forces, which arrive on the blocking
81 * path.
82 * 3. force_cap == 0: force capping requires the final forces (post-reduce).
83 * 4. Integrator is VV or symplectic Euler: only these inertial methods use
84 * step_2; steepest-descent, BD, SD, and NPT are not eligible (NPT virial
85 * is not accumulated during step_2 overlap; BD/SD have no step_2
86 * half-kick).
87 * 5. NPT propagation not in use: the NPT step_2 updates the box pressure and
88 * box length using the virial gathered from forces; it must run after the
89 * full reduce. NPT also implies integ_switch != NVT/SE, so condition 4
90 * already excludes it, but we check explicitly for clarity.
91 * 6. Dipole field tracking not in use
92 * 7. LB-tracer arm not active: TRANS_LB_TRACER particles have forces
93 * transferred to the LB fluid in the integrate loop *after*
94 * calculate_forces and before step_2; with the split-phase path the fluid
95 * coupling would run while the reduction is in flight, leading to incorrect
96 * force accumulation.
97 */
99 // 1. Must have more than one MPI rank.
100 if (::comm_cart.size() <= 1)
101 return false;
102 // 2. ComFixed must be inactive.
103 if (not system.comfixed->get_fixed_types().empty())
104 return false;
105 // 3. Force capping must be off.
106 if (system.get_force_cap() != 0.)
107 return false;
108 // 4. NPT propagation not in use.
109#ifdef ESPRESSO_NPT
110 if (system.propagation->used_propagations &
112 return false;
113#endif
114 // 5. LB-tracer arm not active.
115#ifdef ESPRESSO_VIRTUAL_SITES_INERTIALESS_TRACERS
116 if (system.propagation->used_propagations & PropagationMode::TRANS_LB_TRACER)
117 return false;
118#endif
119 // 6. Dipole field tracking not active.
120#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
121 if (system.dipoles.impl->solver.has_value()) {
122 return false;
123 }
124#endif
125 // 7. Integrator must be VV or symplectic Euler (inertial with step_2
126 // half-kick).
127 auto const integ = system.propagation->integ_switch;
128 return integ == INTEG_METHOD_NVT or integ == INTEG_METHOD_SYMPLECTIC_EULER;
129}
130
131static void force_capping(CellStructure &cell_structure, double force_cap) {
132 if (force_cap > 0.) {
133 auto const force_cap_sq = Utils::sqr(force_cap);
134 cell_structure.for_each_local_particle(
135 [&force_cap, &force_cap_sq](Particle &p) {
136 auto const force_sq = p.force().norm2();
137 if (force_sq > force_cap_sq) {
138 p.force() *= force_cap / std::sqrt(force_sq);
139 }
140 });
141 }
142}
143
144#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
145static void reinit_dip_fld(CellStructure const &cell_structure) {
146 cell_structure.for_each_local_particle(
147 [](Particle &p) { p.dip_fld() = {0., 0., 0.}; });
148}
149#endif
150
151static BondsKernelData
153 auto scatter_force = system.cell_structure->get_scatter_force();
154#ifdef ESPRESSO_NPT
155 auto scatter_virial = system.cell_structure->get_scatter_virial();
156#endif
157 auto const &aosoa = system.cell_structure->get_aosoa();
158 return /* BondsKernelData */ {*system.bonded_ias,
159 *system.bond_breakage,
160 *system.box_geo,
161 scatter_force,
162#ifdef ESPRESSO_NPT
163 scatter_virial,
164#endif
165 aosoa,
166 !system.bond_breakage->breakage_specs.empty()};
167}
168
170 System::System const &system, Utils::Vector3d *virial,
171 auto const &elc_kernel, auto const &coulomb_kernel,
172 auto const &dipoles_kernel, auto const &coulomb_u_kernel) {
173
174 auto const &unique_particles = system.cell_structure->get_unique_particles();
175
176 auto scatter_force = system.cell_structure->get_scatter_force();
177#ifdef ESPRESSO_ROTATION
178 auto scatter_torque = system.cell_structure->get_scatter_torque();
179#endif
180#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
181 auto scatter_dip_fld = system.cell_structure->get_scatter_dip_fld();
182#endif
183#ifdef ESPRESSO_NPT
184 auto scatter_virial = system.cell_structure->get_scatter_virial();
185#endif
186 auto const &aosoa = system.cell_structure->get_aosoa();
187
188 return /* ForcesKernel */ {*system.bonded_ias,
189 *system.nonbonded_ias,
190 get_ptr(coulomb_kernel),
191 get_ptr(dipoles_kernel),
192 get_ptr(elc_kernel),
193 get_ptr(coulomb_u_kernel),
194 system.coulomb,
195 *system.thermostat,
196 *system.box_geo,
197 unique_particles,
198 scatter_force,
199#ifdef ESPRESSO_ROTATION
200 scatter_torque,
201#endif
202#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
203 scatter_dip_fld,
204#endif
205#ifdef ESPRESSO_NPT
206 virial,
207 scatter_virial,
208#endif
209 aosoa,
210 system.maximal_cutoff()};
211}
212
213// Single construction-and-launch site for SpecializedForcesKernel, shared by
214// the with- and without-coulomb branches of the dispatch below.
215template <bool HasCoulomb>
217 InteractionsNonBonded const &nonbonded_ias,
218 CellStructure::AoSoA_pack const &aosoa,
219 CellStructure::ScatterForce scatter_force,
220 CuboidMinimumImage const &minimum_image, double const max_cutoff_sq
221#ifdef ESPRESSO_ELECTROSTATICS
222 ,
223 Coulomb::ShortRangeForceKernel::kernel_type const *coulomb_ptr = nullptr
224#ifdef ESPRESSO_P3M
225 ,
226 CoulombP3M const *p3m = nullptr
227#endif
228#endif
229) {
230 return [=, &nonbonded_ias, &aosoa](CellStructure::ListType const &verlet_list,
231 std::size_t const n) {
232 SpecializedForcesKernel<HasCoulomb> const kernel{nonbonded_ias,
233 aosoa,
234 scatter_force,
235 verlet_list.counts,
236 verlet_list.neighbors,
237 minimum_image,
238 max_cutoff_sq
239#ifdef ESPRESSO_ELECTROSTATICS
240 ,
241 coulomb_ptr
242#ifdef ESPRESSO_P3M
243 ,
244 p3m
245#endif
246#endif
247 };
248 Kokkos::parallel_for("specialized_nonbonded_pairs",
249 Kokkos::RangePolicy<Kokkos::DefaultHostExecutionSpace>(
250 std::size_t{0}, n),
251 kernel);
252 };
253}
254
255// Build the compile-time-specialized Verlet pair loop when the active feature
256// set is covered by SpecializedForcesKernel: cuboid box, no NPT virial, no
257// dipolar or ELC kernel, only allowlisted (central-radial) pair potentials, no
258// Thole pair, and no particle with an exclusion. Returns an empty
259// ShortRangeVerletPairLoop otherwise, leaving cabana_short_range on the
260// generic ForcesKernel path. The specialized kernel is bitwise-identical to
261// the generic one on these systems.
263 System::System const &system,
264 [[maybe_unused]] Utils::Vector3d const *virial,
265 [[maybe_unused]] auto const &elc_kernel, auto const &coulomb_kernel,
266 [[maybe_unused]] auto const &dipoles_kernel) {
267 if (system.box_geo->type() != BoxType::CUBOID)
268 return {};
269#ifdef ESPRESSO_NPT
270 if (virial != nullptr)
271 return {};
272#endif
273#ifdef ESPRESSO_DIPOLES
274 if (get_ptr(dipoles_kernel) != nullptr)
275 return {};
276#endif
277#ifdef ESPRESSO_ELECTROSTATICS
278 if (get_ptr(elc_kernel) != nullptr)
279 return {};
280#endif
281 auto const &nonbonded_ias = *system.nonbonded_ias;
282 // Allowlist over the aggregated pair-potential mask (O(1), maintained by
283 // recalc_maximal_cutoffs). Any type pair with a potential the specialized
284 // kernel does not compute -- Gay-Berne, DPD (in which case the DPD
285 // thermostat could act on the pair), or any future addition -- falls back
286 // to the generic kernel by default.
287 if ((nonbonded_ias.combined_active_pair_mask() &
289 return {};
290#ifdef ESPRESSO_THOLE
291 // Thole damping is not in the pair-potential mask; check its own aggregate.
292 if (nonbonded_ias.any_thole_configured())
293 return {};
294#endif
295 auto &cell_structure = *system.cell_structure;
296 auto const &aosoa = cell_structure.get_aosoa();
297#ifdef ESPRESSO_EXCLUSIONS
298 // The specialized kernel has no exclusion handling. The commit sweep (run by
299 // update_verlet_state earlier in this same force call) accumulates whether
300 // any packed particle carries an exclusion, so this is an O(1) read of the
301 // same population the old per-particle sweep covered (local + ghosts).
302 if (aosoa.has_any_exclusion())
303 return {};
304#endif
305
306 auto scatter_force = cell_structure.get_scatter_force();
307 auto const minimum_image = system.box_geo->cuboid_minimum_image();
308 auto const max_cutoff_sq = Utils::sqr(system.maximal_cutoff());
309
310#ifdef ESPRESSO_ELECTROSTATICS
311 if (auto const *coulomb_ptr = get_ptr(coulomb_kernel);
312 coulomb_ptr != nullptr) {
313 return make_specialized_verlet_pair_loop<true>(
314 nonbonded_ias, aosoa, scatter_force, minimum_image, max_cutoff_sq,
315 coulomb_ptr
316#ifdef ESPRESSO_P3M
317 ,
319#endif
320 );
321 }
322#else
323 static_cast<void>(coulomb_kernel);
324#endif
325
326 return make_specialized_verlet_pair_loop<false>(
327 nonbonded_ias, aosoa, scatter_force, minimum_image, max_cutoff_sq);
328}
329
331 Utils::Vector3d *virial) {
332#ifdef ESPRESSO_CALIPER
334#endif
335
336 auto const &unique_particles = system.cell_structure->get_unique_particles();
337 auto &local_force = system.cell_structure->get_local_force();
338 auto scatter_force = system.cell_structure->get_scatter_force();
339 Kokkos::Experimental::contribute(local_force, scatter_force);
340#ifdef ESPRESSO_ROTATION
341 // when no kernel scattered into the torque buffers this pass, they are
342 // all-zero and both the reduction over replicas and the per-particle
343 // accumulation would only add zeros
344 auto const reduce_torque = system.cell_structure->torque_replicas_dirty();
345 auto &local_torque = system.cell_structure->get_local_torque();
346 if (reduce_torque) {
347 auto scatter_torque = system.cell_structure->get_scatter_torque();
348 Kokkos::Experimental::contribute(local_torque, scatter_torque);
349 }
350#endif
351#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
352 auto const reduce_dip_fld = system.cell_structure->dip_fld_replicas_dirty();
353 auto &local_dip_fld = system.cell_structure->get_local_dip_fld();
354 if (reduce_dip_fld) {
355 auto scatter_dip_fld = system.cell_structure->get_scatter_dip_fld();
356 Kokkos::Experimental::contribute(local_dip_fld, scatter_dip_fld);
357 }
358#endif
359#ifdef ESPRESSO_NPT
360 auto &local_virial = system.cell_structure->get_local_virial();
361 if (system.cell_structure->virial_replicas_dirty()) {
362 auto scatter_virial = system.cell_structure->get_scatter_virial();
363 Kokkos::Experimental::contribute(local_virial, scatter_virial);
364 }
365#endif
366
367 using execution_space = Kokkos::DefaultHostExecutionSpace;
368 Kokkos::RangePolicy<execution_space> policy(std::size_t{0},
369 unique_particles.size());
370 Kokkos::parallel_for("reduction", policy,
371 [&local_force,
372#ifdef ESPRESSO_ROTATION
373 &local_torque, reduce_torque,
374#endif
375#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
376 &local_dip_fld, reduce_dip_fld,
377#endif
378 &unique_particles](std::size_t const i) {
379 Utils::Vector3d force{};
380 force[0] += local_force(i, 0);
381 force[1] += local_force(i, 1);
382 force[2] += local_force(i, 2);
383 unique_particles.at(i)->force() += force;
384#ifdef ESPRESSO_ROTATION
385 if (reduce_torque) {
386 Utils::Vector3d torque{};
387 torque[0] += local_torque(i, 0);
388 torque[1] += local_torque(i, 1);
389 torque[2] += local_torque(i, 2);
390 unique_particles.at(i)->torque() += torque;
391 }
392#endif // ESPRESSO_ROTATION
393#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
394 if (reduce_dip_fld) {
395 Utils::Vector3d dip_fld{};
396 dip_fld[0] += local_dip_fld(i, 0);
397 dip_fld[1] += local_dip_fld(i, 1);
398 dip_fld[2] += local_dip_fld(i, 2);
399 unique_particles.at(i)->dip_fld() += dip_fld;
400 }
401#endif // ESPRESSO_DIPOLE_FIELD_TRACKING
402 });
403 Kokkos::fence();
404
405#ifdef ESPRESSO_NPT
406 if (virial) {
407 (*virial)[0] += local_virial(0);
408 (*virial)[1] += local_virial(1);
409 (*virial)[2] += local_virial(2);
410 }
411#endif
412}
413
415#ifdef ESPRESSO_CALIPER
417#endif
418#ifdef ESPRESSO_CUDA
419 {
420#ifdef ESPRESSO_CALIPER
421 ESPRESSO_CALI_MARK_BEGIN("copy_particles_to_GPU");
422#endif
423 gpu->update();
424#ifdef ESPRESSO_CALIPER
425 ESPRESSO_CALI_MARK_END("copy_particles_to_GPU");
426#endif
427 }
428#endif // ESPRESSO_CUDA
429
430#ifdef ESPRESSO_COLLISION_DETECTION
431 collision_detection->clear_queue();
432 auto const collision_detection_cutoff = collision_detection->cutoff();
433#else
434 auto const collision_detection_cutoff = inactive_cutoff;
435#endif
436 bond_breakage->clear_queue();
437 auto particles = cell_structure->local_particles();
438#ifdef ESPRESSO_NPT
439 if (propagation->used_propagations & PropagationMode::TRANS_LANGEVIN_NPT) {
440 // reset virial part of instantaneous pressure
441 npt_inst_pressure->p_vir = Utils::Vector3d{};
442 }
443#endif
444#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
445 if (dipoles.impl->solver.has_value()) {
446 reinit_dip_fld(*cell_structure);
447 }
448#endif
449
450 // Use combined function instead of two separate calls
451
452 auto const elc_kernel = coulomb.pair_force_elc_kernel();
453 auto const coulomb_kernel = coulomb.pair_force_kernel();
454 auto const dipoles_kernel = dipoles.pair_force_kernel();
455 auto const coulomb_u_kernel = coulomb.pair_energy_kernel();
456 auto *const virial = get_npt_virial();
457
458 // Factory instead of an eager criterion: construction fills an O(n_types^2)
459 // cutoff table, so it only runs where a criterion is actually consumed (the
460 // link-cell fallback and the collision-detection loop below).
461 auto const make_verlet_criterion = [&] {
462 return VerletCriterion<>{*this,
463 cell_structure->get_verlet_skin(),
464 get_interaction_range(),
465 coulomb.cutoff(),
466 dipoles.cutoff(),
467 collision_detection_cutoff};
468 };
469
470 update_verlet_state(*this, collision_detection_cutoff);
471#ifdef ESPRESSO_ELECTROSTATICS
472 if (coulomb.impl->extension) {
473 update_icc_particles();
474 }
475#endif // ESPRESSO_ELECTROSTATICS
477#ifdef ESPRESSO_CALIPER
478 ESPRESSO_CALI_MARK_BEGIN("calc_long_range_forces");
479#endif
480#ifdef ESPRESSO_ELECTROSTATICS
481 coulomb.calc_long_range_force();
482#endif
483#ifdef ESPRESSO_DIPOLES
484 dipoles.calc_long_range_force();
485#endif
486#ifdef ESPRESSO_CALIPER
487 ESPRESSO_CALI_MARK_END("calc_long_range_forces");
488#endif
489
490#ifdef ESPRESSO_CALIPER
491 ESPRESSO_CALI_MARK_BEGIN("cabana_short_range");
492#endif
493 auto &bs = cell_structure->bond_state();
494 auto bonds_kernel_data = create_kokkos_bonds_kernel_data(*this);
495 auto pair_bonds_kernel = PairBondsKernel{
496 bonds_kernel_data, bs.pair_list, bs.pair_ids, get_ptr(coulomb_kernel)};
497 auto angle_bonds_kernel =
498 AngleBondsKernel{bonds_kernel_data, bs.angle_list, bs.angle_ids};
499 auto dihedral_bonds_kernel =
500 DihedralBondsKernel{bonds_kernel_data, bs.dihedral_list, bs.dihedral_ids};
501
502 auto first_neighbor_kernel =
503 create_cabana_neighbor_kernel(*this, virial, elc_kernel, coulomb_kernel,
504 dipoles_kernel, coulomb_u_kernel);
505
506 auto const specialized_pair_loop = create_specialized_verlet_pair_loop(
507 *this, virial, elc_kernel, coulomb_kernel, dipoles_kernel);
508
509 // The specialized pair kernel scatters only into the force view. Record
510 // before the launch whether this pass can write the torque/virial scatter
511 // buffers at all, so their O(n_threads * N) zeroing and reduction can be
512 // skipped otherwise (see CellStructure::reset_local_properties). All other
513 // torque sources (Langevin rotation, virtual sites back-transfer, the
514 // dipolar solvers except dp3m, constraints) write Particle::torque()
515 // directly and never touch the scatter buffers; dp3m marks the flag at its
516 // own scatter site.
517 [[maybe_unused]] auto const generic_pair_path =
518 get_interaction_range() > 0. and
519 (not specialized_pair_loop or
520 propagation->integ_switch == INTEG_METHOD_STEEPEST_DESCENT or
521 not cell_structure->use_verlet_list);
522#ifdef ESPRESSO_ROTATION
523 // Within the generic kernel, only orientation-dependent pair potentials
524 // (Gay-Berne) and the dipolar pair kernel scatter into the torque view.
525 auto const gay_berne_active =
526 nonbonded_ias->pair_potential_active(PairPotential::GayBerne);
527 auto const dipolar_pair_kernel_active =
528#ifdef ESPRESSO_DIPOLES
529 get_ptr(dipoles_kernel) != nullptr;
530#else
531 false;
532#endif
533 if (generic_pair_path and (gay_berne_active or dipolar_pair_kernel_active)) {
534 cell_structure->mark_torque_replicas_dirty();
535#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
536 cell_structure->mark_dip_fld_replicas_dirty();
537#endif
538 // Pair-kernel torques also land on ghost particles and only get home via
539 // the TORQUE ghost reduce. Each torque-scattering kernel therefore needs
540 // a matching arm in orientation_ghosts_needed() (System.cpp).
541 assert(get_force_reduce_ghost_flags() & GHOSTTRANS_TORQUE);
542 }
543#endif // ESPRESSO_ROTATION
544#ifdef ESPRESSO_NPT
545 auto const have_bonds = cell_structure->get_local_pair_bond_numbers() > 0 or
546 cell_structure->get_local_angle_bond_numbers() > 0 or
547 cell_structure->get_local_dihedral_bond_numbers() > 0;
548 if (generic_pair_path or
549 (bonded_ias->maximal_cutoff() >= 0. and have_bonds)) {
550 cell_structure->mark_virial_replicas_dirty();
551 }
552#endif // ESPRESSO_NPT
553
554 cabana_short_range(pair_bonds_kernel, angle_bonds_kernel,
555 dihedral_bonds_kernel, first_neighbor_kernel,
556 *cell_structure, get_interaction_range(),
557 bonded_ias->maximal_cutoff(), make_verlet_criterion,
558 propagation->integ_switch, specialized_pair_loop);
559
560 // Force and Torque reduction
562
563#ifdef ESPRESSO_COLLISION_DETECTION
564 auto collision_kernel = [&collision_detection = *collision_detection](
565 Particle const &p1, Particle const &p2,
566 Distance const &d) {
567 collision_detection.detect_collision(p1, p2, d.dist2);
568 };
569 if (not collision_detection->is_off()) {
570 auto const verlet_criterion = make_verlet_criterion();
571 cell_structure->non_bonded_loop(collision_kernel, verlet_criterion);
572 }
573#endif // ESPRESSO_COLLISION_DETECTION
574
575#ifdef ESPRESSO_CALIPER
576 ESPRESSO_CALI_MARK_END("cabana_short_range");
577#endif
578
579 constraints->add_forces(particles, get_sim_time());
580 oif_global->calculate_forces();
581
582 // Must be done here. Forces need to be ghost-communicated
583 immersed_boundaries->volume_conservation(*cell_structure);
584
585 if (thermostat->lb and (propagation->used_propagations &
587#ifdef ESPRESSO_CALIPER
588 ESPRESSO_CALI_MARK_BEGIN("lb_particle_coupling");
589#endif
590 lb_couple_particles();
591#ifdef ESPRESSO_CALIPER
592 ESPRESSO_CALI_MARK_END("lb_particle_coupling");
593#endif
594 }
595
596#ifdef ESPRESSO_CUDA
597 {
598#ifdef ESPRESSO_CALIPER
599 ESPRESSO_CALI_MARK_BEGIN("copy_forces_from_GPU");
600#endif
601 gpu->copy_forces_to_host(particles, this_node);
602
603#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
604 gpu->copy_dip_fld_to_host(particles, this_node);
605#endif
606
607#ifdef ESPRESSO_CALIPER
608 ESPRESSO_CALI_MARK_END("copy_forces_from_GPU");
609#endif
610 }
611#endif // ESPRESSO_CUDA
612
613#ifdef ESPRESSO_VIRTUAL_SITES_RELATIVE
614 if (propagation->used_propagations &
618 }
619#endif
620#ifdef ESPRESSO_VIRTUAL_SITES_CENTER_OF_MASS
621 if (propagation->used_propagations &
624 }
625#endif
626
628 // Split-phase path: start the ghost force reduction now (non-blocking);
629 // the integrator will run interior-cell step_2, finish the reduce, then
630 // run boundary-cell step_2. comfixed and force_capping are inactive on
631 // this path.
632 assert(comfixed->get_fixed_types().empty() &&
633 "ghost_reduce_overlap: comfixed must be inactive on the eligible "
634 "path");
635 assert(force_cap == 0. &&
636 "ghost_reduce_overlap: force_cap must be 0 on the eligible path");
637 cell_structure->ghosts_reduce_forces_start();
638 } else {
639 // Blocking path: finish the reduce here, then apply comfixed/capping.
640 cell_structure->ghosts_reduce_forces();
641#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
642 if (dipoles.impl->solver.has_value()) {
643 cell_structure->ghosts_reduce_dipole_field();
644 }
645#endif
646
647 // should be pretty late, since it needs to zero out the total force
648 comfixed->apply(particles);
649
650 // Needs to be the last one to be effective
651 force_capping(*cell_structure, force_cap);
652 }
653
654 // mark that forces are now up-to-date
655 propagation->recalc_forces = false;
656}
@ INTEG_METHOD_STEEPEST_DESCENT
@ INTEG_METHOD_NVT
@ INTEG_METHOD_SYMPLECTIC_EULER
Vector implementation and trait types for boost qvm interoperability.
Zero-overhead Caliper guards for the inactive (no CALI_CONFIG) case.
#define ESPRESSO_CALI_MARK_END(name)
Guarded CALI_MARK_END — no-op when inactive.
#define ESPRESSO_CALI_MARK_BEGIN(name)
Guarded CALI_MARK_BEGIN — no-op when inactive.
#define ESPRESSO_CALI_MARK_FUNCTION
Guarded drop-in replacement for CALI_CXX_MARK_FUNCTION.
This file contains everything related to the global cell structure / cell system.
Describes a cell structure / cell system.
void for_each_local_particle(ParticleCallback auto &&f, bool parallel=true) const
Run a kernel on all local particles.
Kokkos::Experimental::ScatterView< double *[3], Kokkos::LayoutRight, memory_space > ScatterForce
Cuboid minimum-image fold parameters for hot pair loops.
Main system class.
double maximal_cutoff() const
Calculate the maximal cutoff of all interactions.
std::shared_ptr< BondedInteractionsMap > bonded_ias
std::shared_ptr< ComFixed > comfixed
std::shared_ptr< BondBreakage::BondBreakage > bond_breakage
Dipoles::Solver dipoles
void calculate_forces()
Calculate all forces.
Definition forces.cpp:414
std::shared_ptr< Propagation > propagation
std::shared_ptr< Thermostat::Thermostat > thermostat
std::shared_ptr< CellStructure > cell_structure
auto get_force_cap() const
Get force_cap.
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
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
const T * get_ptr(std::optional< T > const &opt)
static BondsKernelData create_kokkos_bonds_kernel_data(System::System const &system)
Definition forces.cpp:152
static ShortRangeVerletPairLoop create_specialized_verlet_pair_loop(System::System const &system, Utils::Vector3d const *virial, auto const &elc_kernel, auto const &coulomb_kernel, auto const &dipoles_kernel)
Definition forces.cpp:262
static void reinit_dip_fld(CellStructure const &cell_structure)
Definition forces.cpp:145
static void force_capping(CellStructure &cell_structure, double force_cap)
Definition forces.cpp:131
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:169
static ShortRangeVerletPairLoop make_specialized_verlet_pair_loop(InteractionsNonBonded const &nonbonded_ias, CellStructure::AoSoA_pack const &aosoa, CellStructure::ScatterForce scatter_force, CuboidMinimumImage const &minimum_image, double const max_cutoff_sq, Coulomb::ShortRangeForceKernel::kernel_type const *coulomb_ptr=nullptr, CoulombP3M const *p3m=nullptr)
Definition forces.cpp:216
static bool ghost_reduce_overlap_eligible(System::System const &system)
Eligibility check for the split-phase ghost force reduction.
Definition forces.cpp:98
static void reduce_cabana_forces_and_torques(System::System const &system, Utils::Vector3d *virial)
Definition forces.cpp:330
CoulombP3M const * get_toplevel_p3m_solver(Coulomb::Solver const &coulomb)
The active P3M solver, or nullptr.
constexpr unsigned specialized_kernel_pair_mask
Pair potentials fully handled by SpecializedForcesKernel, i.e.
void init_forces_and_thermostat(System::System const &system)
Combined force initialization and Langevin noise application.
Force calculation.
Ghost particles and particle exchange.
@ GHOSTTRANS_TORQUE
transfer torque (reduced with force; runtime-conditional)
Definition ghosts.hpp:56
ICC is a method that allows to take into account the influence of arbitrarily shaped dielectric inter...
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:171
This file contains all subroutines required to process rotational motion.
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 &make_verlet_criterion, auto const integ_switch, ShortRangeVerletPairLoop const &verlet_pair_loop={})
std::function< void(CellStructure::ListType const &, std::size_t)> ShortRangeVerletPairLoop
ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION bool gay_berne_active(double dist, IA_parameters const &ia_params)
void update_verlet_state(System::System const &system, double const collision_cut)
P3M solver.
Definition p3m.hpp:55
Solver::ShortRangeForceKernel kernel_type
std::unique_ptr< Implementation > impl
Pointer-to-implementation.
Distance vector and length handed to pair kernels.
Struct holding all information for one particle.
Definition Particle.hpp:436
constexpr auto const & dip_fld() const
Definition Particle.hpp:590
constexpr auto const & force() const
Definition Particle.hpp:480
Own-the-loop specialization of the non-bonded pair kernel.