ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
CellSystem.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 "CellSystem.hpp"
21
23
24#include "core/BoxGeometry.hpp"
29#include "core/cells.hpp"
34#include "core/tuning.hpp"
35
36#include <utils/Vector.hpp>
38
39#include <boost/mpi/collectives/gather.hpp>
40#include <boost/variant.hpp>
41
42#include <algorithm>
43#include <iterator>
44#include <set>
45#include <sstream>
46#include <stdexcept>
47#include <string>
48#include <unordered_map>
49#include <utility>
50#include <vector>
51
52namespace ScriptInterface {
53namespace CellSystem {
54
57 {"use_verlet_lists",
58 [this](Variant const &v) {
59 get_cell_structure().use_verlet_list = get_value<bool>(v);
60 },
61 [this]() { return get_cell_structure().use_verlet_list; }},
62 {"node_grid",
63 [this](Variant const &v) {
64 context()->parallel_try_catch([this, &v]() {
65 auto const error_msg = std::string("Parameter 'node_grid'");
66 auto const old_node_grid = ::communicator.node_grid;
67 auto const new_node_grid = get_value<Utils::Vector3i>(v);
68 auto const n_nodes_old = Utils::product(old_node_grid);
69 auto const n_nodes_new = Utils::product(new_node_grid);
70 if (n_nodes_new != n_nodes_old) {
71 std::stringstream reason;
72 reason << ": MPI world size " << n_nodes_old << " incompatible "
73 << "with new node grid [" << new_node_grid << "]";
74 throw std::invalid_argument(error_msg + reason.str());
75 }
76 try {
77 ::communicator.set_node_grid(new_node_grid);
78 get_system().on_node_grid_change();
79 } catch (...) {
80 ::communicator.set_node_grid(old_node_grid);
81 get_system().on_node_grid_change();
82 throw;
83 }
84 });
85 },
86 []() { return ::communicator.node_grid; }},
87 {"skin",
88 [this](Variant const &v) {
89 auto const new_skin = get_value<double>(v);
90 if (new_skin < 0.) {
91 if (context()->is_head_node()) {
92 throw std::domain_error("Parameter 'skin' must be >= 0");
93 }
94 throw Exception("");
95 }
96 get_cell_structure().set_verlet_skin(new_skin);
97 },
98 [this]() { return get_cell_structure().get_verlet_skin(); }},
99 {"decomposition_type", AutoParameter::read_only,
100 [this]() {
101 return cs_type_to_name.at(get_cell_structure().decomposition_type());
102 }},
103 {"n_square_types", AutoParameter::read_only,
104 [this]() {
105 if (get_cell_structure().decomposition_type() !=
107 return Variant{none};
108 }
109 auto const hd = get_hybrid_decomposition();
110 auto const ns_types = hd.get_n_square_types();
111 return Variant{std::vector<int>(ns_types.begin(), ns_types.end())};
112 }},
113 {"cutoff_regular", AutoParameter::read_only,
114 [this]() {
115 if (get_cell_structure().decomposition_type() !=
117 return Variant{none};
118 }
119 auto const hd = get_hybrid_decomposition();
120 return Variant{hd.get_cutoff_regular()};
121 }},
122 {"max_cut_nonbonded", AutoParameter::read_only,
123 [this]() { return get_system().nonbonded_ias->maximal_cutoff(); }},
125 {"interaction_range", AutoParameter::read_only,
126 [this]() { return get_system().get_interaction_range(); }},
127 });
128}
129
130Variant CellSystem::do_call_method(std::string const &name,
131 VariantMap const &params) {
132 if (name == "initialize") {
133 auto const cs_name = get_value<std::string>(params, "name");
134 auto const cs_type = cs_name_to_type.at(cs_name);
135 initialize(cs_type, params);
136 return {};
137 }
138 if (name == "resort") {
139 auto const global_flag = get_value_or<bool>(params, "global_flag", true);
140 return mpi_resort_particles(global_flag);
141 }
142 if (name == "get_state") {
143 auto state = get_parameters();
144 auto const cs_type = get_cell_structure().decomposition_type();
145 if (cs_type == CellStructureType::REGULAR) {
146 auto const rd = get_regular_decomposition();
147 state["cell_grid"] = Variant{rd.cell_grid};
148 state["cell_size"] = Variant{rd.cell_size};
149 } else if (cs_type == CellStructureType::HYBRID) {
150 auto const hd = get_hybrid_decomposition();
151 state["cell_grid"] = Variant{hd.get_cell_grid()};
152 state["cell_size"] = Variant{hd.get_cell_size()};
153 mpi_resort_particles(true); // needed to get correct particle counts
154 state["parts_per_decomposition"] =
155 Variant{std::unordered_map<std::string, Variant>{
156 {"regular", hd.count_particles_in_regular()},
157 {"n_square", hd.count_particles_in_n_square()}}};
158 }
159 state["verlet_reuse"] = get_cell_structure().get_verlet_reuse();
160 state["n_nodes"] = context()->get_comm().size();
161 return state;
162 }
163 if (name == "get_pairs") {
164 std::vector<Variant> out;
165 context()->parallel_try_catch([this, &params, &out]() {
166 auto &system = get_system();
167 system.on_observable_calc();
168 std::vector<std::pair<int, int>> pair_list;
169 auto const distance = get_value<double>(params, "distance");
170 if (boost::get<std::string>(&params.at("types")) != nullptr) {
171 auto const key = get_value<std::string>(params, "types");
172 if (key != "all") {
173 throw std::invalid_argument("Unknown argument types='" + key + "'");
174 }
175 pair_list = get_pairs(system, distance);
176 } else {
177 auto const types = get_value<std::vector<int>>(params, "types");
178 pair_list = get_pairs_of_types(system, distance, types);
179 }
180 Utils::Mpi::gather_buffer(pair_list, context()->get_comm());
181 std::transform(pair_list.begin(), pair_list.end(),
182 std::back_inserter(out),
183 [](std::pair<int, int> const &pair) {
184 return std::vector<int>{pair.first, pair.second};
185 });
186 });
187 return out;
188 }
189 if (name == "get_neighbors") {
190 std::vector<std::vector<int>> neighbors_global;
191 context()->parallel_try_catch([this, &neighbors_global, &params]() {
192 auto &system = get_system();
193 system.on_observable_calc();
194 auto const dist = get_value<double>(params, "distance");
195 auto const pid = get_value<int>(params, "pid");
196 auto const ret = get_short_range_neighbors(system, pid, dist);
197 std::vector<int> neighbors_local;
198 if (ret) {
199 neighbors_local = *ret;
200 }
201 boost::mpi::gather(context()->get_comm(), neighbors_local,
202 neighbors_global, 0);
203 });
204 std::vector<int> neighbors;
205 for (auto const &neighbors_local : neighbors_global) {
206 if (not neighbors_local.empty()) {
207 neighbors = neighbors_local;
208 break;
209 }
210 }
211 return neighbors;
212 }
213 if (name == "non_bonded_loop_trace") {
214 auto &system = get_system();
215 system.on_observable_calc();
216 std::vector<Variant> out;
217 auto pair_list =
218 non_bonded_loop_trace(system, context()->get_comm().rank());
219 Utils::Mpi::gather_buffer(pair_list, context()->get_comm());
220 std::transform(pair_list.begin(), pair_list.end(), std::back_inserter(out),
221 [](PairInfo const &pair) {
222 return std::vector<Variant>{pair.id1, pair.id2,
223 pair.pos1, pair.pos2,
224 pair.vec21, pair.node};
225 });
226 return out;
227 }
228 if (name == "tune_skin") {
229 auto &system = get_system();
230 system.tune_verlet_skin(
231 get_value<double>(params, "min_skin"),
232 get_value<double>(params, "max_skin"), get_value<double>(params, "tol"),
233 get_value<int>(params, "int_steps"),
234 get_value_or<bool>(params, "adjust_max_skin", false));
235 return get_cell_structure().get_verlet_skin();
236 }
237 if (name == "get_max_range") {
238 return get_cell_structure().max_range();
239 }
240 return {};
241}
242
243std::vector<int> CellSystem::mpi_resort_particles(bool global_flag) const {
244 auto &cell_structure = get_cell_structure();
245 cell_structure.resort_particles(global_flag);
247 auto const size = static_cast<int>(cell_structure.local_particles().size());
248 std::vector<int> n_part_per_node;
249 boost::mpi::gather(context()->get_comm(), size, n_part_per_node, 0);
250 return n_part_per_node;
251}
252
253void CellSystem::initialize(CellStructureType const &cs_type,
254 VariantMap const &params) {
255 auto const verlet = get_value_or<bool>(params, "use_verlet_lists", true);
256 auto &system = get_system();
257 m_cell_structure->use_verlet_list = verlet;
258 if (cs_type == CellStructureType::HYBRID) {
259 auto const cutoff_regular = get_value<double>(params, "cutoff_regular");
260 auto const ns_types =
261 get_value_or<std::vector<int>>(params, "n_square_types", {});
262 auto n_square_types = std::set<int>{ns_types.begin(), ns_types.end()};
263 m_cell_structure->set_hybrid_decomposition(cutoff_regular, n_square_types);
264 } else {
265 system.set_cell_structure_topology(cs_type);
266 }
267}
268
269} // namespace CellSystem
270} // namespace ScriptInterface
CellStructureType
Cell structure topology.
@ HYBRID
Hybrid decomposition.
@ REGULAR
Regular decomposition.
Vector implementation and trait types for boost qvm interoperability.
double maximal_cutoff_bonded()
Calculate the maximal cutoff of bonded interactions, required to determine the cell size for communic...
Data structures for bonded interactions.
std::vector< PairInfo > non_bonded_loop_trace(System::System const &system, int const rank)
Returns pairs of particle ids, positions and distance as seen by the non-bonded loop.
Definition cells.cpp:177
std::vector< std::pair< int, int > > get_pairs_of_types(System::System const &system, double const distance, std::vector< int > const &types)
Get pairs closer than distance if both their types are in types.
Definition cells.cpp:167
boost::optional< std::vector< int > > get_short_range_neighbors(System::System const &system, int const pid, double const distance)
Get ids of particles that are within a certain distance of another particle.
Definition cells.cpp:119
std::vector< std::pair< int, int > > get_pairs(System::System const &system, double const distance)
Get pairs closer than distance from the cells.
Definition cells.cpp:159
This file contains everything related to the global cell structure / cell system.
void add_parameters(std::vector< AutoParameter > &&params)
Variant do_call_method(std::string const &name, VariantMap const &params) override
virtual void parallel_try_catch(std::function< void()> const &cb) const =0
virtual boost::mpi::communicator const & get_comm() const =0
VariantMap get_parameters() const
Get current parameters.
boost::string_ref name() const
Context * context() const
Responsible context.
Communicator communicator
This file contains the asynchronous MPI communication.
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:82
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:80
constexpr const None none
None-"literal".
Definition Variant.hpp:63
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.
T product(Vector< T, N > const &v)
Definition Vector.hpp:359
Various procedures concerning interactions between particles.
static auto & get_cell_structure()
void clear_particle_node()
Invalidate particle_node.
Particles creation and deletion.
static SteepestDescentParameters params
Currently active steepest descent instance.
Utils::Vector3i node_grid
void set_node_grid(Utils::Vector3i const &value)
Set new Cartesian topology.
static constexpr const ReadOnly read_only