ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
bond_forces_kokkos.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <config/config.hpp>
23
24#include "aosoa_pack.hpp"
26#include "forces_inline.hpp"
27
28#include <utils/Vector.hpp>
29
30#include <Kokkos_Core.hpp>
31
32#include <omp.h>
33
34#include <cstddef>
35#include <optional>
36#include <variant>
37
49
55
60 : data(data_), bond_list(std::move(bond_list_)),
61 bond_ids(std::move(bond_ids_)), coulomb_kernel(coulomb_kernel_) {}
62
63 ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION void
64 operator()(std::size_t idx) const {
65 auto const &bonded_ias = data.bonded_ias;
66 auto const &box_geo = data.box_geo;
67 auto &local_force = data.local_force;
68 auto const &aosoa = data.aosoa;
69 auto &bond_breakage = data.bond_breakage;
70#ifdef ESPRESSO_NPT
71 auto &local_virial = data.local_virial;
72#endif
73 auto const has_breakage_specs = data.has_breakage_specs;
74 auto const bond_id = bond_ids(idx);
75
76 // TODO: omp_get_thread_num() is only available for the OpenMP backend.
77 // This should be updated when using other Kokkos backends.
78 auto const thread_id = omp_get_thread_num();
79
80 auto const i = bond_list(idx, 0);
81 auto const j = bond_list(idx, 1);
82 auto const &iaparams = *bonded_ias.at(bond_id);
83
84 auto const dx =
85 box_geo.get_mi_vector(aosoa.get_vector_at(aosoa.position, i),
86 aosoa.get_vector_at(aosoa.position, j));
87 // Consider for bond breakage
88 if (has_breakage_specs &&
89 bond_breakage.check_and_handle_breakage(
90 aosoa.id(i), {{aosoa.id(j), std::nullopt}}, bond_id, dx.norm())) {
91 return;
92 }
93
94 if (auto const *iap = std::get_if<ThermalizedBond>(&iaparams)) {
95 auto const result = iap->forces(
96#ifdef ESPRESSO_MASS
97 aosoa.mass(i), aosoa.mass(j),
98#else
99 1.0, 1.0,
100#endif
101 aosoa.get_vector_at(aosoa.velocity, i),
102 aosoa.get_vector_at(aosoa.velocity, j), aosoa.id(i), aosoa.id(j), dx);
103 if (result) {
104 auto const &forces = result.value();
105
106 local_force(i, thread_id, 0) += std::get<0>(forces)[0];
107 local_force(i, thread_id, 1) += std::get<0>(forces)[1];
108 local_force(i, thread_id, 2) += std::get<0>(forces)[2];
109 local_force(j, thread_id, 0) += std::get<1>(forces)[0];
110 local_force(j, thread_id, 1) += std::get<1>(forces)[1];
111 local_force(j, thread_id, 2) += std::get<1>(forces)[2];
112 } else {
113 auto partner_id = aosoa.id(j);
114 bond_broken_error(aosoa.id(i), {&partner_id, 1});
115 }
116 return;
117 }
118
119 auto const result =
120 calc_bond_pair_force(iaparams, dx,
121#ifdef ESPRESSO_ELECTROSTATICS
122 aosoa.charge(i) * aosoa.charge(j), coulomb_kernel
123#else
124 0.0, nullptr
125#endif
126 );
127
128 if (result) {
129 auto const f = result.value();
130 local_force(i, thread_id, 0) += f[0];
131 local_force(i, thread_id, 1) += f[1];
132 local_force(i, thread_id, 2) += f[2];
133 local_force(j, thread_id, 0) -= f[0];
134 local_force(j, thread_id, 1) -= f[1];
135 local_force(j, thread_id, 2) -= f[2];
136#ifdef ESPRESSO_NPT
137 auto const virial = hadamard_product(f, dx);
138 local_virial(thread_id, 0) += virial[0];
139 local_virial(thread_id, 1) += virial[1];
140 local_virial(thread_id, 2) += virial[2];
141#endif
142 } else {
143 auto partner_id = aosoa.id(j);
144 bond_broken_error(aosoa.id(i), {&partner_id, 1});
145 }
146 }
147};
148
153
157 : data(data_), bond_list(std::move(bond_list_)),
158 bond_ids(std::move(bond_ids_)) {}
159
160 ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION void
161 operator()(std::size_t idx) const {
162 auto const &bonded_ias = data.bonded_ias;
163 auto const &box_geo = data.box_geo;
164 auto &local_force = data.local_force;
165 auto const &aosoa = data.aosoa;
166 auto &bond_breakage = data.bond_breakage;
167 auto const has_breakage_specs = data.has_breakage_specs;
168 auto const bond_id = bond_ids(idx);
169
170 // TODO: omp_get_thread_num() is only available for the OpenMP backend.
171 // This should be updated when using other Kokkos backends.
172 auto const thread_id = omp_get_thread_num();
173
174 auto const i = bond_list(idx, 0);
175 auto const j = bond_list(idx, 1);
176 auto const k = bond_list(idx, 2);
177 auto const &iaparams = *bonded_ias.at(bond_id);
178
179 auto const pos1 = aosoa.get_vector_at(aosoa.position, i);
180 auto const pos2 = aosoa.get_vector_at(aosoa.position, j);
181 auto const pos3 = aosoa.get_vector_at(aosoa.position, k);
182 auto const vec1 = box_geo.get_mi_vector(pos2, pos1);
183 auto const vec2 = box_geo.get_mi_vector(pos3, pos1);
184
185 // Consider for bond breakage
186 if (has_breakage_specs &&
187 bond_breakage.check_and_handle_breakage(
188 aosoa.id(i), {{aosoa.id(j), aosoa.id(k)}}, bond_id,
189 box_geo.get_mi_vector(pos2, pos3).norm())) {
190 return;
191 }
192 if (std::get_if<OifGlobalForcesBond>(&iaparams)) {
193 return;
194 }
195
196 auto const result = calc_bonded_three_body_force(iaparams, vec1, vec2);
197
198 if (result) {
199 auto const &forces = result.value();
200
201 local_force(i, thread_id, 0) += std::get<0>(forces)[0];
202 local_force(i, thread_id, 1) += std::get<0>(forces)[1];
203 local_force(i, thread_id, 2) += std::get<0>(forces)[2];
204 local_force(j, thread_id, 0) += std::get<1>(forces)[0];
205 local_force(j, thread_id, 1) += std::get<1>(forces)[1];
206 local_force(j, thread_id, 2) += std::get<1>(forces)[2];
207 local_force(k, thread_id, 0) += std::get<2>(forces)[0];
208 local_force(k, thread_id, 1) += std::get<2>(forces)[1];
209 local_force(k, thread_id, 2) += std::get<2>(forces)[2];
210 } else {
211 std::array<int, 2> pids = {aosoa.id(j), aosoa.id(k)};
212 bond_broken_error(aosoa.id(i), {pids.data(), 2});
213 }
214 }
215};
216
221
225 : data(data_), bond_list(std::move(bond_list_)),
226 bond_ids(std::move(bond_ids_)) {}
227
228 ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION void
229 operator()(std::size_t idx) const {
230 auto const &bonded_ias = data.bonded_ias;
231 auto const &box_geo = data.box_geo;
232 auto &local_force = data.local_force;
233 auto const &aosoa = data.aosoa;
234 auto const bond_id = bond_ids(idx);
235
236 // TODO: omp_get_thread_num() is only available for the OpenMP backend.
237 // This should be updated when using other Kokkos backends.
238 auto const thread_id = omp_get_thread_num();
239
240 auto const i = bond_list(idx, 0);
241 auto const j = bond_list(idx, 1);
242 auto const k = bond_list(idx, 2);
243 auto const m = bond_list(idx, 3);
244 auto const &iaparams = *bonded_ias.at(bond_id);
245
246 auto const pos1 = aosoa.get_vector_at(aosoa.position, i);
247 auto const pos2 = aosoa.get_vector_at(aosoa.position, j);
248 auto const pos3 = aosoa.get_vector_at(aosoa.position, k);
249 auto const pos4 = aosoa.get_vector_at(aosoa.position, m);
250 auto const vel1 = aosoa.get_vector_at(aosoa.velocity, i);
251 auto const vel3 = aosoa.get_vector_at(aosoa.velocity, k);
252 auto const image1 = aosoa.get_vector_at(aosoa.image, i);
253
254 auto const result = calc_bonded_four_body_force(
255 iaparams, box_geo, pos1, pos2, pos3, pos4, vel1, vel3, image1);
256
257 if (result) {
258 auto const &forces = result.value();
259
260 local_force(i, thread_id, 0) += std::get<0>(forces)[0];
261 local_force(i, thread_id, 1) += std::get<0>(forces)[1];
262 local_force(i, thread_id, 2) += std::get<0>(forces)[2];
263 local_force(j, thread_id, 0) += std::get<1>(forces)[0];
264 local_force(j, thread_id, 1) += std::get<1>(forces)[1];
265 local_force(j, thread_id, 2) += std::get<1>(forces)[2];
266 local_force(k, thread_id, 0) += std::get<2>(forces)[0];
267 local_force(k, thread_id, 1) += std::get<2>(forces)[1];
268 local_force(k, thread_id, 2) += std::get<2>(forces)[2];
269 local_force(m, thread_id, 0) += std::get<3>(forces)[0];
270 local_force(m, thread_id, 1) += std::get<3>(forces)[1];
271 local_force(m, thread_id, 2) += std::get<3>(forces)[2];
272 } else {
273 std::array<int, 3> pids = {aosoa.id(j), aosoa.id(k), aosoa.id(m)};
274 bond_broken_error(aosoa.id(i), {pids.data(), 3});
275 }
276 }
277};
Vector implementation and trait types for boost qvm interoperability.
#define ESPRESSO_ATTR_ALWAYS_INLINE
void bond_broken_error(int id, std::span< const int > partner_ids)
container for bonded interactions.
Force calculation.
ESPRESSO_ATTR_ALWAYS_INLINE std::optional< Utils::Vector3d > calc_bond_pair_force(Bonded_IA_Parameters const &iaparams, Utils::Vector3d const &dx, double const q1q2, Coulomb::ShortRangeForceKernel::kernel_type const *kernel)
Compute the bonded interaction force between particle pairs.
ESPRESSO_ATTR_ALWAYS_INLINE std::optional< std::tuple< Utils::Vector3d, Utils::Vector3d, Utils::Vector3d, Utils::Vector3d > > calc_bonded_four_body_force(Bonded_IA_Parameters const &iaparams, BoxGeometry const &box_geo, Utils::Vector3d const &pos1, Utils::Vector3d const &pos2, Utils::Vector3d const &pos3, Utils::Vector3d const &pos4, Utils::Vector3d const &vel1, Utils::Vector3d const &vel3, Utils::Vector3i const &image1)
ESPRESSO_ATTR_ALWAYS_INLINE std::optional< std::tuple< Utils::Vector3d, Utils::Vector3d, Utils::Vector3d > > calc_bonded_three_body_force(Bonded_IA_Parameters const &iaparams, Utils::Vector3d const &vec1, Utils::Vector3d const &vec2)
auto hadamard_product(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:377
STL namespace.
ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION void operator()(std::size_t idx) const
LocalBondState::AngleBondIDType bond_ids
AngleBondsKernel(BondsKernelData data_, LocalBondState::AngleBondlistType bond_list_, LocalBondState::AngleBondIDType bond_ids_)
LocalBondState::AngleBondlistType bond_list
CellStructure::AoSoA_pack const & aosoa
bool const has_breakage_specs
BondBreakage::BondBreakage & bond_breakage
CellStructure::VirialType & local_virial
CellStructure::ForceType & local_force
BondedInteractionsMap const & bonded_ias
BoxGeometry const & box_geo
Solver::ShortRangeForceKernel kernel_type
ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION void operator()(std::size_t idx) const
DihedralBondsKernel(BondsKernelData data_, LocalBondState::DihedralBondlistType bond_list_, LocalBondState::DihedralBondIDType bond_ids_)
LocalBondState::DihedralBondIDType bond_ids
LocalBondState::DihedralBondlistType bond_list
PairBondsKernel(BondsKernelData data_, LocalBondState::PairBondlistType bond_list_, LocalBondState::PairBondIDType bond_ids_, Coulomb::ShortRangeForceKernel::kernel_type const *coulomb_kernel_)
LocalBondState::PairBondIDType bond_ids
ESPRESSO_ATTR_ALWAYS_INLINE KOKKOS_INLINE_FUNCTION void operator()(std::size_t idx) const
Coulomb::ShortRangeForceKernel::kernel_type const *const coulomb_kernel
LocalBondState::PairBondlistType bond_list
BondsKernelData data