ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
ParticleList.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 "ParticleList.hpp"
21#include "ParticleHandle.hpp"
22#include "ParticleSlice.hpp"
23
27
29#include "core/exclusions.hpp"
32
33#include <utils/Vector.hpp>
36
37#include <boost/mpi/collectives.hpp>
38#include <boost/mpi/communicator.hpp>
39
40#include <algorithm>
41#include <cstddef>
42#include <memory>
43#include <stdexcept>
44#include <string>
45#include <unordered_map>
46#include <utility>
47#include <vector>
48
49namespace ScriptInterface {
50namespace Particles {
51
52#ifdef EXCLUSIONS
53/**
54 * @brief Use the bond topology to automatically add exclusions between
55 * particles that are up to @c n_bonds_max bonds apart in a chain.
56 */
57static void auto_exclusions(boost::mpi::communicator const &comm,
58 int const n_bonds_max) {
59 // bookkeeping of particle exclusions, with their n-bond distance
60 std::unordered_map<int, std::vector<std::pair<int, int>>> partners;
61 std::vector<int> bonded_pairs;
62
63 auto &system = ::System::get_system();
64 auto &cell_structure = *system.cell_structure;
65
66 // determine initial connectivity
67 for (auto const &p : cell_structure.local_particles()) {
68 auto const pid1 = p.id();
69 for (auto const bond : p.bonds()) {
70 if (bond.partner_ids().size() == 1u) {
71 auto const pid2 = bond.partner_ids()[0];
72 if (pid1 != pid2) {
73 bonded_pairs.emplace_back(pid1);
74 bonded_pairs.emplace_back(pid2);
75 }
76 }
77 }
78 }
79
80 Utils::Mpi::gather_buffer(bonded_pairs, comm);
81
82 if (comm.rank() == 0) {
83 auto const add_partner = [&partners](int pid1, int pid2, int n_bonds) {
84 if (pid2 == pid1)
85 return;
86 for (auto const &partner : partners[pid1])
87 if (partner.first == pid2)
88 return;
89 partners[pid1].emplace_back(pid2, n_bonds);
90 };
91
92 for (auto it = bonded_pairs.begin(); it != bonded_pairs.end(); it += 2) {
93 add_partner(it[0], it[1], 1);
94 add_partner(it[1], it[0], 1);
95 }
96
97 // determine transient connectivity
98 for (int iteration = 1; iteration < n_bonds_max; iteration++) {
99 std::vector<int> pids;
100 for (auto const &kv : partners) {
101 pids.emplace_back(kv.first);
102 }
103 for (auto const pid1 : pids) {
104 // loop over partners (counter-based loops due to iterator invalidation)
105 // NOLINTNEXTLINE(modernize-loop-convert)
106 for (std::size_t i = 0u; i < partners[pid1].size(); ++i) {
107 auto const [pid2, dist21] = partners[pid1][i];
108 if (dist21 > n_bonds_max)
109 continue;
110 // loop over all partners of the partner
111 // NOLINTNEXTLINE(modernize-loop-convert)
112 for (std::size_t j = 0u; j < partners[pid2].size(); ++j) {
113 auto const [pid3, dist32] = partners[pid2][j];
114 auto const dist31 = dist32 + dist21;
115 if (dist31 > n_bonds_max)
116 continue;
117 add_partner(pid1, pid3, dist31);
118 add_partner(pid3, pid1, dist31);
119 }
120 }
121 }
122 }
123 }
124
125 boost::mpi::broadcast(comm, partners, 0);
126 for (auto const &kv : partners) {
127 auto const pid1 = kv.first;
128 auto const &partner_list = kv.second;
129 for (auto const &partner : partner_list) {
130 auto const pid2 = partner.first;
131 if (auto p1 = cell_structure.get_local_particle(pid1)) {
132 add_exclusion(*p1, pid2);
133 }
134 if (auto p2 = cell_structure.get_local_particle(pid2)) {
135 add_exclusion(*p2, pid1);
136 }
137 }
138 }
139 system.on_particle_change();
140}
141#endif // EXCLUSIONS
142
143Variant ParticleList::do_call_method(std::string const &name,
144 VariantMap const &params) {
145#ifdef EXCLUSIONS
146 if (name == "auto_exclusions") {
147 auto const distance = get_value<int>(params, "distance");
148 auto_exclusions(context()->get_comm(), distance);
149 return {};
150 }
151#endif // EXCLUSIONS
152 if (name == "get_highest_particle_id") {
154 }
155 if (name == "clear") {
157 return {};
158 }
159 if (not context()->is_head_node()) {
160 return {};
161 }
162 if (name == "by_id") {
163 return std::dynamic_pointer_cast<ParticleHandle>(
164 context()->make_shared("Particles::ParticleHandle",
165 {{"id", get_value<int>(params, "p_id")},
166 {"__cell_structure", m_cell_structure.lock()},
167 {"__bonded_ias", m_bonded_ias.lock()}}));
168 }
169 if (name == "by_ids") {
170 return context()->make_shared(
171 "Particles::ParticleSlice",
172 {{"id_selection", get_value<std::vector<int>>(params, "id_selection")},
173 {"__cell_structure", m_cell_structure.lock()},
174 {"__bonded_ias", m_bonded_ias.lock()}});
175 }
176 if (name == "get_n_part") {
177 return get_n_part();
178 }
179 if (name == "get_particle_ids") {
180 return get_particle_ids();
181 }
182 if (name == "particle_exists") {
183 return particle_exists(get_value<int>(params, "p_id"));
184 }
185 if (name == "add_particle") {
186 assert(not params.contains("bonds"));
187 VariantMap local_params = params;
188 local_params["__cell_structure"] = m_cell_structure.lock();
189 local_params["__bonded_ias"] = m_bonded_ias.lock();
190 auto so = std::dynamic_pointer_cast<ParticleHandle>(
191 context()->make_shared("Particles::ParticleHandle", local_params));
192#ifdef EXCLUSIONS
193 if (params.count("exclusions")) {
194 so->call_method("set_exclusions", {{"p_ids", params.at("exclusions")}});
195 }
196#endif // EXCLUSIONS
197 return so->get_parameter("id");
198 }
199 return {};
200}
201
202} // namespace Particles
203} // namespace ScriptInterface
Vector implementation and trait types for boost qvm interoperability.
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.
boost::string_ref name() const
Context * context() const
Responsible context.
void add_exclusion(Particle &p, int p_id)
Insert an exclusion if not already set.
static void auto_exclusions(boost::mpi::communicator const &comm, int const n_bonds_max)
Use the bond topology to automatically add exclusions between particles that are up to n_bonds_max bo...
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:69
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectRef, Utils::Vector3b, Utils::Vector3i, Utils::Vector2d, Utils::Vector3d, Utils::Vector4d, std::vector< int >, std::vector< double >, std::vector< boost::recursive_variant_ >, std::unordered_map< int, boost::recursive_variant_ >, std::unordered_map< std::string, boost::recursive_variant_ > >::type Variant
Possible types for parameters.
Definition Variant.hpp:67
System & get_system()
void gather_buffer(std::vector< T, Allocator > &buffer, boost::mpi::communicator const &comm, int root=0)
Gather buffer with different size on each node.
void remove_all_particles()
Remove all particles.
int get_maximal_particle_id()
Get maximal particle id.
std::vector< int > get_particle_ids()
Get all particle ids.
int get_n_part()
Get number of particles.
bool particle_exists(int p_id)
Check if particle exists.
Particles creation and deletion.
static SteepestDescentParameters params
Currently active steepest descent instance.