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 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 old_type = p->type();
124 auto const &new_type = types[i];
125 if (new_type < 0) {
126 throw std::domain_error(error_msg("type", "must be an integer >= 0"));
127 }
128 system.nonbonded_ias->make_particle_type_exist(new_type);
130 p->type() = new_type;
131 }
132 }
133}
134
135#ifdef ESPRESSO_ELECTROSTATICS
136static void set_particles_charges(std::vector<int> const &pids,
137 std::vector<double> const &charges,
138 CellStructure &cell_structure,
140 for (std::size_t i = 0; i < pids.size(); ++i) {
141 auto const pid = pids[i];
142 auto p = cell_structure.get_local_particle(pid);
143 if (p != nullptr and not p->is_ghost()) {
144 p->q() = charges[i];
145 }
146 }
147 system.on_particle_charge_change();
148}
149#endif // ESPRESSO_ELECTROSTATICS
150
152 if (params.contains("__cell_structure")) {
154 params, "__cell_structure");
155 so->configure(*this);
156 m_cell_structure = so;
157 }
158 if (params.contains("__bonded_ias")) {
160 params, "__bonded_ias");
161 }
162 m_id_selection = get_value<std::vector<int>>(params, "id_selection");
163 m_chunk_size = get_value_or<int>(params, "prefetch_chunk_size", 10000);
164 if (not context()->is_head_node()) {
165 return;
166 }
167 for (auto const pid : m_id_selection) {
168 if (not particle_exists(pid)) {
169 throw std::out_of_range("Particle does not exist: " +
170 std::to_string(pid));
171 }
172 }
173}
174
176 VariantMap const &params) {
177 if (name == "set_param_parallel") {
178 auto const param_name = get_value<std::string>(params, "name");
179 if (not params.contains("values")) {
180 context()->parallel_try_catch([&]() {
181 if (param_name == "bonds") {
182 if (not params.contains("all_bonds_ids")) {
183 throw Exception("Parameter 'all_bonds_ids' is missing");
184 }
185 if (not params.contains("all_bonds_partner_ids")) {
186 throw Exception("Parameter 'all_bonds_partner_ids' is missing");
187 }
188 } else {
189 throw Exception("Parameter 'values' is missing");
190 }
191 });
192 }
193 // Handle parameters with special setters
194 if (m_special_parameters.contains(param_name)) {
195 context()->parallel_try_catch([&]() {
196 if (param_name == "pos") {
198 m_id_selection,
199 get_value<std::vector<Utils::Vector3d>>(params, "values"));
200 } else if (param_name == "type") {
201 set_particles_types(m_id_selection,
202 get_value<std::vector<int>>(params, "values"),
203 *get_cell_structure(), *get_system());
204 }
205#ifdef ESPRESSO_ELECTROSTATICS
206 else if (param_name == "q") {
207 std::vector<double> charges;
208 if (is_type<std::vector<int>>(params.at("values"))) {
209 auto tmp = get_value<std::vector<int>>(params, "values");
210 charges = std::vector<double>(tmp.begin(), tmp.end());
211 } else {
212 charges = get_value<std::vector<double>>(params, "values");
213 }
214 set_particles_charges(m_id_selection, charges, *get_cell_structure(),
215 *get_system());
216
217 }
218#endif // ESPRESSO_ELECTROSTATICS
219#ifdef ESPRESSO_EXCLUSIONS
220 else if (param_name == "exclusions") {
221 auto const excluded_pids =
224 m_id_selection,
225 get_value<std::vector<std::vector<int>>>(params, "values"),
226 context()->get_comm(), *get_cell_structure(), *get_system());
227 }
228#endif // ESPRESSO_EXCLUSIONS
229 else if (param_name == "bonds") {
231 m_id_selection,
232 get_value<std::vector<std::vector<int>>>(params, "all_bonds_ids"),
233 get_value<std::vector<std::vector<std::vector<int>>>>(
234 params, "all_bonds_partner_ids"),
235 *get_cell_structure(), *get_system());
236 }
237 });
238 } else {
239 // Handle generic parameters
240 context()->parallel_try_catch([&]() {
241 std::visit(
242 [&](auto &&vals) {
244 context(), m_cell_structure.lock(),
245 m_bonded_ias.lock());
246 },
247 params.at("values"));
248 });
249 }
250 return {};
251 }
252 if (name == "get_param_parallel") {
253 auto const param_name = get_value<std::string>(params, "name");
254
255 // handle special optimized properties
256 if (param_name == "type") {
257 auto const getter{[](Particle const &p) { return p.type(); }};
258 return get_particles_properties<int>(m_id_selection, getter, context(),
259 *get_cell_structure());
260 }
261 if (param_name == "q") {
262 auto const getter{[](Particle const &p) { return p.q(); }};
263 return get_particles_properties<double>(m_id_selection, getter, context(),
264 *get_cell_structure());
265 }
266 if (param_name == "pos") {
267 auto const &box_geo = *get_system()->box_geo;
268 auto const getter = [&box_geo](Particle const &p) {
269 return box_geo.unfolded_position(p.pos(), p.image_box());
270 };
272 m_id_selection, getter, context(), *get_cell_structure());
273 }
274 if (param_name == "pos_folded") {
275 auto const &box_geo = *get_system()->box_geo;
276 auto const getter = [&box_geo](Particle const &p) {
277 return box_geo.folded_position(p.pos());
278 };
280 m_id_selection, getter, context(), *get_cell_structure());
281 }
282
283 // handle all other particle properties using expensive MPI reductions
284 if (!context()->is_head_node()) {
285 return {};
286 }
287 std::vector<Variant> result;
288 result.reserve(m_id_selection.size());
289 auto so = std::dynamic_pointer_cast<ParticleModifier>(
290 context()->make_shared("Particles::ParticleModifier",
291 {{"id", -1},
292 {"__cell_structure", m_cell_structure.lock()},
293 {"__bonded_ias", m_bonded_ias.lock()}}));
294 for (int pid : m_id_selection) {
295 so->set_pid(pid);
296 result.emplace_back(so->get_parameter(param_name));
297 }
298 return result;
299 }
300
301 if (not context()->is_head_node()) {
302 return {};
303 }
304 if (name == "prefetch_particle_data") {
305 auto p_ids = get_value<std::vector<int>>(params, "chunk");
307 return {};
308 }
309 if (name == "get_particle") {
310 return context()->make_shared(
311 "Particles::ParticleHandle",
312 {{"id", get_value<int>(params, "p_id")},
313 {"__cell_structure", m_cell_structure.lock()},
314 {"__bonded_ias", m_bonded_ias.lock()}});
315 }
316 return {};
317}
318
319} // namespace Particles
320} // 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.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
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 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.
void on_particle_type_change(int p_id, int old_type, int new_type)
bool particle_exists(int p_id)
Check if particle exists.
Particles creation and deletion.
static SteepestDescentParameters params
Currently active steepest descent instance.
Struct holding all information for one particle.
Definition Particle.hpp:450
auto const & q() const
Definition Particle.hpp:593
auto const & type() const
Definition Particle.hpp:473
auto const & bonds() const
Definition Particle.hpp:483
Recursive variant implementation.
Definition Variant.hpp:84