ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
script_interface/system/System.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013-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 "System.hpp"
21
22#include "config/config.hpp"
23
24#include "core/BoxGeometry.hpp"
25#include "core/Particle.hpp"
29#include "core/cells.hpp"
34#include "core/propagation.hpp"
35#include "core/rotation.hpp"
38
49
50#include <utils/Vector.hpp>
52
53#include <boost/mpi/collectives.hpp>
54
55#include <algorithm>
56#include <array>
57#include <cassert>
58#include <cmath>
59#include <functional>
60#include <memory>
61#include <stdexcept>
62#include <string>
63#include <type_traits>
64#include <vector>
65
66namespace ScriptInterface {
67namespace System {
68
69static bool system_created = false;
70
71/** @brief Container for leaves of the system class. */
73 Leaves() = default;
74 std::shared_ptr<CellSystem::CellSystem> cell_system;
75 std::shared_ptr<Integrators::IntegratorHandle> integrator;
76 std::shared_ptr<Thermostat::Thermostat> thermostat;
77 std::shared_ptr<Analysis::Analysis> analysis;
78 std::shared_ptr<Galilei::ComFixed> comfixed;
79 std::shared_ptr<Galilei::Galilei> galilei;
80 std::shared_ptr<BondBreakage::BreakageSpecs> bond_breakage;
81 std::shared_ptr<LeesEdwards::LeesEdwards> lees_edwards;
82#ifdef ELECTROSTATICS
83 std::shared_ptr<Coulomb::Container> electrostatics;
84#endif
85#ifdef DIPOLES
86 std::shared_ptr<Dipoles::Container> magnetostatics;
87#endif
88};
89
90System::System() : m_instance{}, m_leaves{std::make_shared<Leaves>()} {
91 auto const add_parameter =
92 [this, ptr = m_leaves.get()](std::string key, auto(Leaves::*member)) {
94 key.c_str(),
95 [this, ptr, member, key](Variant const &val) {
96 auto &dst = ptr->*member;
97 if (dst != nullptr) {
98 throw WriteError(key);
99 }
100 dst = get_value<std::remove_reference_t<decltype(dst)>>(val);
101 dst->bind_system(m_instance);
102 },
103 [ptr, member]() { return ptr->*member; })});
104 };
105
106 add_parameters({
107 {"box_l",
108 [this](Variant const &v) {
109 context()->parallel_try_catch([&]() {
110 auto const new_value = get_value<Utils::Vector3d>(v);
111 if (not(new_value > Utils::Vector3d::broadcast(0.))) {
112 throw std::domain_error("Attribute 'box_l' must be > 0");
113 }
114 m_instance->veto_boxl_change();
115 m_instance->box_geo->set_length(new_value);
116 m_instance->on_boxl_change();
117 });
118 },
119 [this]() { return m_instance->box_geo->length(); }},
120 {"periodicity",
121 [this](Variant const &v) {
122 auto const periodicity = get_value<Utils::Vector3b>(v);
123 for (unsigned int i = 0u; i < 3u; ++i) {
124 m_instance->box_geo->set_periodic(i, periodicity[i]);
125 }
126 context()->parallel_try_catch(
127 [&]() { m_instance->on_periodicity_change(); });
128 },
129 [this]() {
130 return Utils::Vector3b{m_instance->box_geo->periodic(0),
131 m_instance->box_geo->periodic(1),
132 m_instance->box_geo->periodic(2)};
133 }},
134 {"min_global_cut",
135 [this](Variant const &v) {
136 context()->parallel_try_catch([&]() {
137 auto const new_value = get_value<double>(v);
138 if (new_value < 0. and new_value != INACTIVE_CUTOFF) {
139 throw std::domain_error("Attribute 'min_global_cut' must be >= 0");
140 }
141 m_instance->set_min_global_cut(new_value);
142 });
143 },
144 [this]() { return m_instance->get_min_global_cut(); }},
145 {"max_oif_objects", ::max_oif_objects},
146 });
147 add_parameter("cell_system", &Leaves::cell_system);
148 add_parameter("integrator", &Leaves::integrator);
149 add_parameter("thermostat", &Leaves::thermostat);
150 add_parameter("analysis", &Leaves::analysis);
151 add_parameter("comfixed", &Leaves::comfixed);
152 add_parameter("galilei", &Leaves::galilei);
153 add_parameter("bond_breakage", &Leaves::bond_breakage);
154 add_parameter("lees_edwards", &Leaves::lees_edwards);
155#ifdef ELECTROSTATICS
156 add_parameter("electrostatics", &Leaves::electrostatics);
157#endif
158#ifdef DIPOLES
159 add_parameter("magnetostatics", &Leaves::magnetostatics);
160#endif
161}
162
163void System::do_construct(VariantMap const &params) {
164 /* When reloading the system state from a checkpoint file,
165 * the order of global variables instantiation matters.
166 * The @c box_l must be set before any other global variable.
167 * All these globals re-initialize the cell system, and we
168 * cannot use the default-constructed @c box_geo when e.g.
169 * long-range interactions exist in the system, otherwise
170 * runtime errors about the local geometry being smaller
171 * than the interaction range would be raised.
172 */
173 m_instance = ::System::System::create();
174 ::System::set_system(m_instance);
175
176 // domain decomposition can only be set after box_l is set
177 m_instance->set_cell_structure_topology(CellStructureType::NSQUARE);
178 do_set_parameter("box_l", params.at("box_l"));
179 m_instance->set_cell_structure_topology(CellStructureType::REGULAR);
180
181 m_instance->lb.bind_system(m_instance);
182 m_instance->ek.bind_system(m_instance);
183
184 for (auto const &key : get_parameter_insertion_order()) {
185 if (key != "box_l" and params.count(key) != 0ul) {
186 do_set_parameter(key, params.at(key));
187 }
188 }
189}
190
191static void rotate_system(CellStructure &cell_structure, double phi,
192 double theta, double alpha) {
193 auto const particles = cell_structure.local_particles();
194
195 // Calculate center of mass
196 Utils::Vector3d local_com{};
197 double local_mass = 0.0;
198
199 for (auto const &p : particles) {
200 if (not p.is_virtual()) {
201 local_com += p.mass() * p.pos();
202 local_mass += p.mass();
203 }
204 }
205
206 auto const total_mass =
207 boost::mpi::all_reduce(comm_cart, local_mass, std::plus<>());
208 auto const com =
209 boost::mpi::all_reduce(comm_cart, local_com, std::plus<>()) / total_mass;
210
211 // Rotation axis in Cartesian coordinates
212 Utils::Vector3d axis;
213 axis[0] = std::sin(theta) * std::cos(phi);
214 axis[1] = std::sin(theta) * std::sin(phi);
215 axis[2] = std::cos(theta);
216
217 // Rotate particle coordinates
218 for (auto &p : particles) {
219 // Move the center of mass of the system to the origin
220 p.pos() = com + Utils::vec_rotate(axis, alpha, p.pos() - com);
221#ifdef ROTATION
222 local_rotate_particle(p, axis, alpha);
223#endif
224 }
225
229}
230
231/** Rescale all particle positions in direction @p dir by a factor @p scale.
232 * @param cell_structure cell structure
233 * @param dir direction to scale (0/1/2 = x/y/z, 3 = x+y+z isotropically)
234 * @param scale factor by which to rescale (>1: stretch, <1: contract)
235 */
236static void rescale_particles(CellStructure &cell_structure, int dir,
237 double scale) {
238 for (auto &p : cell_structure.local_particles()) {
239 if (dir < 3)
240 p.pos()[dir] *= scale;
241 else {
242 p.pos() *= scale;
243 }
244 }
245}
246
247Variant System::do_call_method(std::string const &name,
248 VariantMap const &parameters) {
249 if (name == "is_system_created") {
250 return system_created;
251 }
252 if (name == "lock_system_creation") {
253 system_created = true;
254 return {};
255 }
256 if (name == "rescale_boxl") {
257 auto &box_geo = *m_instance->box_geo;
258 auto const coord = get_value<int>(parameters, "coord");
259 auto const length = get_value<double>(parameters, "length");
260 assert(coord != 3 or ((box_geo.length()[0] == box_geo.length()[1]) and
261 (box_geo.length()[1] == box_geo.length()[2])));
262 auto const scale = (coord == 3) ? length * box_geo.length_inv()[0]
263 : length * box_geo.length_inv()[coord];
264 context()->parallel_try_catch([&]() {
265 if (length <= 0.) {
266 throw std::domain_error("Parameter 'd_new' must be > 0");
267 }
268 m_instance->veto_boxl_change(true);
269 });
270 auto new_value = Utils::Vector3d{};
271 if (coord == 3) {
272 new_value = Utils::Vector3d::broadcast(length);
273 } else {
274 new_value = box_geo.length();
275 new_value[coord] = length;
276 }
277 // when shrinking, rescale the particles first
278 if (scale <= 1.) {
279 rescale_particles(*m_instance->cell_structure, coord, scale);
280 m_instance->on_particle_change();
281 }
282 m_instance->box_geo->set_length(new_value);
283 m_instance->on_boxl_change();
284 if (scale > 1.) {
285 rescale_particles(*m_instance->cell_structure, coord, scale);
286 m_instance->on_particle_change();
287 }
288 return {};
289 }
290 if (name == "setup_type_map") {
291 auto const types = get_value<std::vector<int>>(parameters, "type_list");
292 for (auto const type : types) {
293 ::init_type_map(type);
294 }
295 return {};
296 }
297 if (name == "number_of_particles") {
298 auto const type = get_value<int>(parameters, "type");
299 return ::number_of_particles_with_type(type);
300 }
301 if (name == "velocity_difference") {
302 auto const pos1 = get_value<Utils::Vector3d>(parameters, "pos1");
303 auto const pos2 = get_value<Utils::Vector3d>(parameters, "pos2");
304 auto const v1 = get_value<Utils::Vector3d>(parameters, "v1");
305 auto const v2 = get_value<Utils::Vector3d>(parameters, "v2");
306 return m_instance->box_geo->velocity_difference(pos2, pos1, v2, v1);
307 }
308 if (name == "distance_vec") {
309 auto const pos1 = get_value<Utils::Vector3d>(parameters, "pos1");
310 auto const pos2 = get_value<Utils::Vector3d>(parameters, "pos2");
311 return m_instance->box_geo->get_mi_vector(pos2, pos1);
312 }
313 if (name == "rotate_system") {
314 rotate_system(*m_instance->cell_structure,
315 get_value<double>(parameters, "phi"),
316 get_value<double>(parameters, "theta"),
317 get_value<double>(parameters, "alpha"));
318 m_instance->on_particle_change();
319 m_instance->update_dependent_particles();
320 return {};
321 }
322 if (name == "get_propagation_modes_enum") {
324 }
325 if (name == "session_shutdown") {
326 if (m_instance) {
327 if (&::System::get_system() == m_instance.get()) {
329 }
330 assert(m_instance.use_count() == 1l);
331 m_instance.reset();
332 }
333 return {};
334 }
335 return {};
336}
337
338} // namespace System
339} // namespace ScriptInterface
@ NSQUARE
Atom decomposition (N-square).
@ REGULAR
Regular decomposition.
Vector implementation and trait types for boost qvm interoperability.
float u[3]
This file contains everything related to the global cell structure / cell system.
void add_parameters(std::vector< AutoParameter > &&params)
static std::shared_ptr< System > create()
static Vector< T, N > broadcast(T const &s)
Create a vector that has all entries set to one value.
Definition Vector.hpp:110
boost::mpi::communicator comm_cart
The communicator.
This file contains the defaults for ESPResSo.
This file contains the asynchronous MPI communication.
@ DATA_PART_PROPERTIES
Particle::p.
@ DATA_PART_POSITION
Particle::r.
static void rotate_system(CellStructure &cell_structure, double phi, double theta, double alpha)
static void rescale_particles(CellStructure &cell_structure, int dir, double scale)
Rescale all particle positions in direction dir by a factor scale.
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:82
auto make_unordered_map_of_variants(std::unordered_map< K, V > const &v)
Definition Variant.hpp:93
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
void reset_system()
System & get_system()
void set_system(std::shared_ptr< System > new_instance)
Vector3d vec_rotate(const Vector3d &axis, double angle, const Vector3d &vector)
Rotate a vector around an axis.
Various procedures concerning interactions between particles.
constexpr double INACTIVE_CUTOFF
Cutoff for deactivated interactions.
int max_oif_objects
Routines to calculate the OIF global forces energy or/and and force for a particle triple (triangle f...
void init_type_map(int type)
Particles creation and deletion.
std::unordered_map< std::string, int > propagation_flags_map()
Convert PropagationMode::PropagationMode to name/value pairs.
This file contains all subroutines required to process rotational motion.
void local_rotate_particle(Particle &p, const Utils::Vector3d &axis_space_frame, const double phi)
Rotate the particle p around the NORMALIZED axis aSpaceFrame by amount phi.
Definition rotation.hpp:133
static SteepestDescentParameters params
Currently active steepest descent instance.
Describes a cell structure / cell system.
void update_ghosts_and_resort_particle(unsigned data_parts)
Update ghost particles, with particle resort if needed.
void set_resort_particles(Cells::Resort level)
Increase the local resort level at least to level.
ParticleRange local_particles() const
Description and getter/setter for a parameter.
Container for leaves of the system class.
std::shared_ptr< Thermostat::Thermostat > thermostat
std::shared_ptr< Integrators::IntegratorHandle > integrator
std::shared_ptr< Dipoles::Container > magnetostatics
std::shared_ptr< CellSystem::CellSystem > cell_system
std::shared_ptr< BondBreakage::BreakageSpecs > bond_breakage
std::shared_ptr< Coulomb::Container > electrostatics
std::shared_ptr< LeesEdwards::LeesEdwards > lees_edwards