ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
ParticleSlice.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022-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#include "ParticleSlice.hpp"
21#include "ParticleHandle.hpp"
22
23#include "core/bonds.hpp"
27
32
33#include <utils/Vector.hpp>
35
36#include <algorithm>
37#include <functional>
38#include <iterator>
39#include <memory>
40#include <stdexcept>
41#include <string>
42#include <utility>
43#include <variant>
44#include <vector>
45
46namespace ScriptInterface {
47namespace Particles {
48
50 std::vector<int> const &pids,
51 std::vector<std::vector<int>> const &all_bonds_ids,
52 std::vector<std::vector<std::vector<int>>> const &all_bonds_partner_ids,
53 ::CellStructure &cell_structure, ::System::System &system) {
54 for (std::size_t i = 0; i < pids.size(); ++i) {
55 auto const pid = pids[i];
56 auto const bonds_ids = all_bonds_ids[i];
58 // Remove old bonds
59 auto p = cell_structure.get_local_particle(pid);
60 if (p != nullptr and not p->is_ghost()) {
61 p->bonds().clear();
62 }
63 // Add new bonds
64 for (std::size_t j = 0; j < bonds_ids.size(); ++j) {
65 std::vector<int> particle_ids = {pid};
66 std::ranges::copy(bonds_partner_ids[j], std::back_inserter(particle_ids));
68 system.on_particle_change();
69 }
70 }
71}
72
73#ifdef ESPRESSO_EXCLUSIONS
74static void
75set_particles_exclusions(std::vector<int> const &pids,
76 std::vector<std::vector<int>> const &exclusion_lists,
77 boost::mpi::communicator const &comm,
78 ::CellStructure &cell_structure,
80 for (std::size_t i = 0; i < pids.size(); ++i) {
81 auto const pid = pids[i];
82 auto const &exclusion_list = exclusion_lists[i];
83 for (auto const excluded_pid : exclusion_list) { // collective communication
84 particle_exclusion_sanity_checks(pid, excluded_pid, cell_structure, comm);
85 }
86 auto p = cell_structure.get_local_particle(pid);
87 if (p != nullptr and not p->is_ghost()) {
88 // Remove all excluded ids of this particle
89 for (auto const old_excluded_pid : p->exclusions()) {
90 local_remove_exclusion(pid, old_excluded_pid, cell_structure);
91 }
92 // Add new excluded ids for this particle
93 for (auto const excluded_pid : exclusion_list) {
94 if (not p->has_exclusion(excluded_pid)) {
95 local_add_exclusion(pid, excluded_pid, cell_structure);
96 }
97 }
98 }
99 }
100 system.on_particle_change();
101}
102#endif // ESPRESSO_EXCLUSIONS
103
104static void
105set_particles_positions(std::vector<int> const &pids,
106 std::vector<Utils::Vector3d> const &positions) {
107 for (std::size_t i = 0; i < pids.size(); ++i) {
108 auto const pid = pids[i];
109 auto const &pos = positions[i];
110 particle_checks(pid, pos);
111 set_particle_pos(pid, pos);
112 }
113}
114
115static void set_particles_types(std::vector<int> const &pids,
116 std::vector<int> const &types,
117 CellStructure &cell_structure,
119 for (std::size_t i = 0; i < pids.size(); ++i) {
120 auto const pid = pids[i];
121 auto p = cell_structure.get_local_particle(pid);
122 if (p != nullptr and not p->is_ghost()) {
123 auto const &new_type = types[i];
124 if (new_type < 0) {
125 throw std::domain_error(error_msg("type", "must be an integer >= 0"));
126 }
127 system.nonbonded_ias->make_particle_type_exist(new_type);
128 p->type() = new_type;
129 }
130 }
131}
132
133#ifdef ESPRESSO_ELECTROSTATICS
134static void set_particles_charges(std::vector<int> const &pids,
135 std::vector<double> const &charges,
136 CellStructure &cell_structure,
138 for (std::size_t i = 0; i < pids.size(); ++i) {
139 auto const pid = pids[i];
140 auto p = cell_structure.get_local_particle(pid);
141 if (p != nullptr and not p->is_ghost()) {
142 p->q() = charges[i];
143 }
144 }
145 system.on_particle_charge_change();
146}
147#endif // ESPRESSO_ELECTROSTATICS
148
150 if (params.contains("__cell_structure")) {
152 params, "__cell_structure");
153 so->configure(*this);
154 m_cell_structure = so;
155 }
156 if (params.contains("__bonded_ias")) {
158 params, "__bonded_ias");
159 }
160 m_id_selection = get_value<std::vector<int>>(params, "id_selection");
161 m_chunk_size = get_value_or<int>(params, "prefetch_chunk_size", 10000);
162 if (not context()->is_head_node()) {
163 return;
164 }
165 for (auto const pid : m_id_selection) {
166 if (not particle_exists(pid)) {
167 throw std::out_of_range("Particle does not exist: " +
168 std::to_string(pid));
169 }
170 }
171}
172
174 VariantMap const &params) {
175 if (name == "set_param_parallel") {
176 auto const param_name = get_value<std::string>(params, "name");
177 if (not params.contains("values")) {
178 context()->parallel_try_catch([&]() {
179 if (param_name == "bonds") {
180 if (not params.contains("all_bonds_ids")) {
181 throw Exception("Parameter 'all_bonds_ids' is missing");
182 }
183 if (not params.contains("all_bonds_partner_ids")) {
184 throw Exception("Parameter 'all_bonds_partner_ids' is missing");
185 }
186 } else {
187 throw Exception("Parameter 'values' is missing");
188 }
189 });
190 }
191 // Handle parameters with special setters
192 if (m_special_parameters.contains(param_name)) {
193 context()->parallel_try_catch([&]() {
194 if (param_name == "pos") {
196 m_id_selection,
197 get_value<std::vector<Utils::Vector3d>>(params, "values"));
198 } else if (param_name == "type") {
199 set_particles_types(m_id_selection,
200 get_value<std::vector<int>>(params, "values"),
201 *get_cell_structure(), *get_system());
202 }
203#ifdef ESPRESSO_ELECTROSTATICS
204 else if (param_name == "q") {
205 std::vector<double> charges;
206 if (is_type<std::vector<int>>(params.at("values"))) {
207 auto tmp = get_value<std::vector<int>>(params, "values");
208 charges = std::vector<double>(tmp.begin(), tmp.end());
209 } else {
210 charges = get_value<std::vector<double>>(params, "values");
211 }
212 set_particles_charges(m_id_selection, charges, *get_cell_structure(),
213 *get_system());
214
215 }
216#endif // ESPRESSO_ELECTROSTATICS
217#ifdef ESPRESSO_EXCLUSIONS
218 else if (param_name == "exclusions") {
219 auto const excluded_pids =
220 get_value<std::vector<std::vector<int>>>(params, "values");
222 m_id_selection,
223 get_value<std::vector<std::vector<int>>>(params, "values"),
224 context()->get_comm(), *get_cell_structure(), *get_system());
225 }
226#endif // ESPRESSO_EXCLUSIONS
227 else if (param_name == "bonds") {
229 m_id_selection,
230 get_value<std::vector<std::vector<int>>>(params, "all_bonds_ids"),
231 get_value<std::vector<std::vector<std::vector<int>>>>(
232 params, "all_bonds_partner_ids"),
233 *get_cell_structure(), *get_system());
234 }
235 });
236 } else {
237 // Handle generic parameters
238 context()->parallel_try_catch([&]() {
239 std::visit(
240 [&](auto &&vals) {
241 set_from_vector_like(m_id_selection, param_name, vals, context(),
242 m_cell_structure.lock(),
243 m_bonded_ias.lock());
244 },
245 params.at("values"));
246 });
247 }
248 return {};
249 }
250 if (name == "get_param_parallel") {
251 auto const param_name = get_value<std::string>(params, "name");
252
253 // handle special optimized properties
254 if (param_name == "type") {
255 auto const getter{[](Particle const &p) { return p.type(); }};
256 return get_particles_properties<int>(m_id_selection, getter, context(),
257 *get_cell_structure());
258 }
259 if (param_name == "q") {
260 auto const getter{[](Particle const &p) { return p.q(); }};
261 return get_particles_properties<double>(m_id_selection, getter, context(),
262 *get_cell_structure());
263 }
264 if (param_name == "pos") {
265 auto const &box_geo = *get_system()->box_geo;
266 auto const getter = [&box_geo](Particle const &p) {
267 return box_geo.unfolded_position(p.pos(), p.image_box());
268 };
270 m_id_selection, getter, context(), *get_cell_structure());
271 }
272 if (param_name == "pos_folded") {
273 auto const &box_geo = *get_system()->box_geo;
274 auto const getter = [&box_geo](Particle const &p) {
275 return box_geo.folded_position(p.pos());
276 };
278 m_id_selection, getter, context(), *get_cell_structure());
279 }
280
281 // handle all other particle properties using expensive MPI reductions
282 if (!context()->is_head_node()) {
283 return {};
284 }
285 std::vector<Variant> result;
286 result.reserve(m_id_selection.size());
287 VariantMap const obj_params{{"id", -1},
288 {"__cell_structure", m_cell_structure.lock()},
289 {"__bonded_ias", m_bonded_ias.lock()}};
290 auto so = std::dynamic_pointer_cast<ParticleModifier>(
291 context()->make_shared("Particles::ParticleModifier", obj_params));
292 for (int pid : m_id_selection) {
293 so->set_pid(pid);
294 result.emplace_back(so->get_parameter(param_name));
295 }
296 return result;
297 }
298
299 if (not context()->is_head_node()) {
300 return {};
301 }
302 if (name == "prefetch_particle_data") {
303 auto p_ids = get_value<std::vector<int>>(params, "chunk");
305 return {};
306 }
307 if (name == "get_particle") {
308 VariantMap const obj_params{{"id", get_value<int>(params, "p_id")},
309 {"__cell_structure", m_cell_structure.lock()},
310 {"__bonded_ias", m_bonded_ias.lock()}};
311 return context()->make_shared("Particles::ParticleHandle", obj_params);
312 }
313 return {};
314}
315
316} // namespace Particles
317} // namespace ScriptInterface
ScriptInterface::Context decorates ScriptInterface::ObjectHandle objects with a context: a creation p...
Vector implementation and trait types for boost qvm interoperability.
bool add_bond(System::System &system, int bond_id, std::vector< int > const &particle_ids)
Add a bond to a particle.
Definition bonds.cpp:25
Describes a cell structure / cell system.
Particle * get_local_particle(int id)
Get a local particle by id.
virtual void parallel_try_catch(std::function< void()> const &cb) const =0
virtual std::shared_ptr< ObjectHandle > make_shared(std::string const &name, const VariantMap &parameters)=0
Get a new reference counted instance of a script interface by name.
virtual bool is_head_node() const =0
Context * context() const
Responsible context.
std::string_view name() const
Variant do_call_method(std::string const &name, VariantMap const &params) override
void do_construct(VariantMap const &params) override
Main system class.
static void set_particles_charges(std::vector< int > const &pids, std::vector< double > const &charges, CellStructure &cell_structure, ::System::System &system)
static void set_particles_bonds(std::vector< int > const &pids, std::vector< std::vector< int > > const &all_bonds_ids, std::vector< std::vector< std::vector< int > > > const &all_bonds_partner_ids, ::CellStructure &cell_structure, ::System::System &system)
void particle_exclusion_sanity_checks(int pid1, int pid2, ::CellStructure &cell_structure, auto const &comm)
void set_from_vector_like(std::vector< int > const &pids, std::string const &param_name, Container const &values, Context *context, std::shared_ptr< CellSystem::CellSystem > cell_structure, std::shared_ptr< Interactions::BondedInteractions > bonded_ias)
void local_remove_exclusion(int pid1, int pid2, ::CellStructure &cell_structure)
Locally remove an exclusion to a particle.
static void set_particles_types(std::vector< int > const &pids, std::vector< int > const &types, CellStructure &cell_structure, ::System::System &system)
void particle_checks(int p_id, Utils::Vector3d const &pos)
auto error_msg(std::string const &name, std::string const &reason)
static void set_particles_exclusions(std::vector< int > const &pids, std::vector< std::vector< int > > const &exclusion_lists, boost::mpi::communicator const &comm, ::CellStructure &cell_structure, ::System::System &system)
static void set_particles_positions(std::vector< int > const &pids, std::vector< Utils::Vector3d > const &positions)
void local_add_exclusion(int pid1, int pid2, ::CellStructure &cell_structure)
Locally add an exclusion to a particle.
constexpr bool is_type(Variant const &v)
Check is a Variant holds a specific type.
Definition Variant.hpp:159
T get_value(Variant const &v)
Extract value of specific type T from a Variant.
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:133
Various procedures concerning interactions between particles.
void set_particle_pos(int p_id, Utils::Vector3d const &pos)
Move particle to a new position.
void prefetch_particle_data(std::span< const int > in_ids)
Fetch a range of particle into the fetch cache.
bool particle_exists(int p_id)
Check if particle exists.
Particles creation and deletion.
Struct holding all information for one particle.
Definition Particle.hpp:436
constexpr auto const & bonds() const
Definition Particle.hpp:473
constexpr auto const & q() const
Definition Particle.hpp:597
Recursive variant implementation.
Definition Variant.hpp:84