Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
core/system/System.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014-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 "config/config.hpp"
21
22#include "System.hpp"
23#include "System.impl.hpp"
24
25#include "BoxGeometry.hpp"
26#include "LocalBox.hpp"
27#include "PropagationMode.hpp"
28#include "accumulators/AutoUpdateAccumulators.hpp"
34#include "collision_detection/CollisionDetection.hpp"
35#include "communication.hpp"
37#include "errorhandling.hpp"
38#include "npt.hpp"
39#include "particle_node.hpp"
40#include "thermostat.hpp"
42
43#include <utils/Vector.hpp>
45
46#include <boost/mpi/collectives/all_reduce.hpp>
47
48#include <algorithm>
49#include <cstddef>
50#include <functional>
51#include <memory>
52#include <stdexcept>
53#include <utility>
54
55namespace System {
56
57static std::shared_ptr<System> instance = System::create();
58
59std::shared_ptr<System> System::create() {
60 auto handle = std::make_shared<System>(Private());
61 handle->initialize();
62 return handle;
63}
64
66 box_geo = std::make_shared<BoxGeometry>();
67 local_geo = std::make_shared<LocalBox>();
68 cell_structure = std::make_shared<CellStructure>(*box_geo);
69 propagation = std::make_shared<Propagation>();
70 bonded_ias = std::make_shared<BondedInteractionsMap>();
71 thermostat = std::make_shared<Thermostat::Thermostat>();
72 nonbonded_ias = std::make_shared<InteractionsNonBonded>();
73 comfixed = std::make_shared<ComFixed>();
74 galilei = std::make_shared<Galilei>();
75 oif_global = std::make_shared<OifGlobal>();
76 immersed_boundaries = std::make_shared<ImmersedBoundaries>();
77#ifdef COLLISION_DETECTION
78 collision_detection =
79 std::make_shared<CollisionDetection::CollisionDetection>();
80#endif
81 bond_breakage = std::make_shared<BondBreakage::BondBreakage>();
82 lees_edwards = std::make_shared<LeesEdwards::LeesEdwards>();
83 auto_update_accumulators =
84 std::make_shared<Accumulators::AutoUpdateAccumulators>();
85 constraints = std::make_shared<Constraints::Constraints>();
86#ifdef NPT
87 nptiso = std::make_shared<NptIsoParameters>();
88 npt_inst_pressure = std::make_shared<InstantaneousPressure>();
89#endif
90 reinit_thermo = true;
91 time_step = -1.;
92 sim_time = 0.;
93 force_cap = 0.;
94 min_global_cut = INACTIVE_CUTOFF;
95}
96
97void System::initialize() {
98 auto handle = shared_from_this();
99 cell_structure->bind_system(handle);
100 lees_edwards->bind_system(handle);
101 immersed_boundaries->bind_system(handle);
102 bonded_ias->bind_system(handle);
103 thermostat->bind_system(handle);
104 nonbonded_ias->bind_system(handle);
105 oif_global->bind_system(handle);
106 immersed_boundaries->bind_system(handle);
107#ifdef COLLISION_DETECTION
108 collision_detection->bind_system(handle);
109#endif
110 auto_update_accumulators->bind_system(handle);
111 constraints->bind_system(handle);
112#ifdef CUDA
113 gpu.bind_system(handle);
114 gpu.initialize();
115#endif
116 lb.bind_system(handle);
117 ek.bind_system(handle);
118}
119
120void reset_system() { instance.reset(); }
121
122void set_system(std::shared_ptr<System> new_instance) {
123 instance = new_instance;
124}
125
127
128void System::set_time_step(double value) {
129 if (value <= 0.)
130 throw std::domain_error("time_step must be > 0.");
131 if (lb.is_solver_set()) {
132 lb.veto_time_step(value);
133 }
134 if (ek.is_solver_set()) {
135 ek.veto_time_step(value);
136 }
137 time_step = value;
138 on_timestep_change();
139}
140
141void System::check_kT(double value) const {
142 if (lb.is_solver_set()) {
143 lb.veto_kT(value);
144 }
145 if (ek.is_solver_set()) {
146 ek.veto_kT(value);
147 }
148}
149
150void System::set_force_cap(double value) {
151 force_cap = value;
152 propagation->recalc_forces = true;
153}
154
155void System::set_min_global_cut(double value) {
156 min_global_cut = value;
157 on_verlet_skin_change();
158}
159
161 if (topology == CellStructureType::REGULAR) {
162 if (cell_structure->decomposition_type() == CellStructureType::REGULAR) {
163 // get fully connected info from exising regular decomposition
164 auto &old_regular_decomposition =
165 dynamic_cast<RegularDecomposition const &>(
166 std::as_const(*cell_structure).decomposition());
167 cell_structure->set_regular_decomposition(
168 get_interaction_range(),
169 old_regular_decomposition.fully_connected_boundary());
170 } else { // prev. decomposition is not a regular decomposition
171 cell_structure->set_regular_decomposition(get_interaction_range(), {});
172 }
173 } else if (topology == CellStructureType::NSQUARE) {
174 cell_structure->set_atom_decomposition();
175 } else {
176 assert(topology == CellStructureType::HYBRID);
177 /* Get current HybridDecomposition to extract n_square_types */
178 auto &old_hybrid_decomposition = dynamic_cast<HybridDecomposition const &>(
179 std::as_const(*cell_structure).decomposition());
180 cell_structure->set_hybrid_decomposition(
181 old_hybrid_decomposition.get_cutoff_regular(),
182 old_hybrid_decomposition.get_n_square_types());
183 }
184}
185
187 set_cell_structure_topology(cell_structure->decomposition_type());
188}
189
190void System::on_boxl_change(bool skip_method_adaption) {
191 update_local_geo();
192 rebuild_cell_structure();
193
194 /* Now give methods a chance to react to the change in box length */
195 if (not skip_method_adaption) {
196 lb.on_boxl_change();
197 ek.on_boxl_change();
198#ifdef ELECTROSTATICS
199 coulomb.on_boxl_change();
200#endif
201#ifdef DIPOLES
202 dipoles.on_boxl_change();
203#endif
204 }
205 constraints->on_boxl_change();
206}
207
208void System::veto_boxl_change(bool skip_particle_checks) const {
209 if (not skip_particle_checks) {
210 auto const n_part = boost::mpi::all_reduce(
211 ::comm_cart, cell_structure->local_particles().size(), std::plus<>());
212 if (n_part > 0ul) {
213 throw std::runtime_error(
214 "Cannot reset the box length when particles are present");
215 }
216 }
217 constraints->veto_boxl_change();
218 lb.veto_boxl_change();
219 ek.veto_boxl_change();
220}
221
223 update_local_geo();
224 lb.on_node_grid_change();
225 ek.on_node_grid_change();
226#ifdef ELECTROSTATICS
227 coulomb.on_node_grid_change();
228#endif
229#ifdef DIPOLES
230 dipoles.on_node_grid_change();
231#endif
232 rebuild_cell_structure();
233}
234
236#ifdef ELECTROSTATICS
237 coulomb.on_periodicity_change();
238#endif
239
240#ifdef DIPOLES
241 dipoles.on_periodicity_change();
242#endif
243
244#ifdef STOKESIAN_DYNAMICS
245 if (propagation->integ_switch == INTEG_METHOD_SD) {
246 if (box_geo->periodic(0u) or box_geo->periodic(1u) or box_geo->periodic(2u))
247 runtimeErrorMsg() << "Stokesian Dynamics requires periodicity "
248 << "(False, False, False)\n";
249 }
250#endif
251 on_verlet_skin_change();
252}
253
256 lb.on_cell_structure_change();
257 ek.on_cell_structure_change();
258#ifdef ELECTROSTATICS
259 coulomb.on_cell_structure_change();
260#endif
261#ifdef DIPOLES
262 dipoles.on_cell_structure_change();
263#endif
264}
265
266void System::on_thermostat_param_change() { reinit_thermo = true; }
267
269 rebuild_cell_structure();
270#ifdef ELECTROSTATICS
271 coulomb.on_coulomb_change();
272#endif
273#ifdef DIPOLES
274 dipoles.on_dipoles_change();
275#endif
276 on_short_range_ia_change();
277}
278
280 lb.on_temperature_change();
281 ek.on_temperature_change();
282}
283
285 lb.on_timestep_change();
286 ek.on_timestep_change();
287 on_thermostat_param_change();
288}
289
291 rebuild_cell_structure();
292 propagation->recalc_forces = true;
293}
294
296 nonbonded_ias->recalc_maximal_cutoffs();
297 rebuild_cell_structure();
298 on_thermostat_param_change();
299 propagation->recalc_forces = true;
300}
301
303#ifdef ELECTROSTATICS
304 coulomb.on_coulomb_change();
305#endif
306 on_short_range_ia_change();
307}
308
310#ifdef DIPOLES
311 dipoles.on_dipoles_change();
312#endif
313 on_short_range_ia_change();
314}
315
316void System::on_constraint_change() { propagation->recalc_forces = true; }
317
319 propagation->recalc_forces = true;
320}
321
323 cell_structure->update_ghosts_and_resort_particle(get_global_ghost_flags());
324 propagation->recalc_forces = true;
325}
326
328 if (cell_structure->decomposition_type() == CellStructureType::HYBRID) {
329 cell_structure->set_resort_particles(Cells::RESORT_GLOBAL);
330 } else {
331 cell_structure->set_resort_particles(Cells::RESORT_LOCAL);
332 }
333#ifdef ELECTROSTATICS
334 coulomb.on_particle_change();
335#endif
336#ifdef DIPOLES
337 dipoles.on_particle_change();
338#endif
339 propagation->recalc_forces = true;
340
341 /* the particle information is no longer valid */
343}
344
346#ifdef ELECTROSTATICS
347 coulomb.on_particle_change();
348#endif
349}
350
352#ifdef VIRTUAL_SITES
353#ifdef VIRTUAL_SITES_RELATIVE
354 vs_relative_update_particles(*cell_structure, *box_geo);
355#endif
356 cell_structure->update_ghosts_and_resort_particle(get_global_ghost_flags());
357#endif
358
359#ifdef ELECTROSTATICS
360 update_icc_particles();
361#endif
362
363 // Here we initialize volume conservation
364 // This function checks if the reference volumes have been set and if
365 // necessary calculates them
366 immersed_boundaries->init_volume_conservation(*cell_structure);
367}
368
370 /* Prepare particle structure: Communication step: number of ghosts and ghost
371 * information */
372 cell_structure->update_ghosts_and_resort_particle(get_global_ghost_flags());
373 update_dependent_particles();
374
375#ifdef ELECTROSTATICS
376 coulomb.on_observable_calc();
377#endif
378
379#ifdef DIPOLES
380 dipoles.on_observable_calc();
381#endif
382
384}
385
386void System::on_lees_edwards_change() { lb.on_lees_edwards_change(); }
387
393
395 auto max_cut = INACTIVE_CUTOFF;
396 max_cut = std::max(max_cut, get_min_global_cut());
397#ifdef ELECTROSTATICS
398 max_cut = std::max(max_cut, coulomb.cutoff());
399#endif
400#ifdef DIPOLES
401 max_cut = std::max(max_cut, dipoles.cutoff());
402#endif
403 if (::communicator.size > 1) {
404 // If there is just one node, the bonded cutoff can be omitted
405 // because bond partners are always on the local node.
406 max_cut = std::max(max_cut, bonded_ias->maximal_cutoff());
407 }
408 max_cut = std::max(max_cut, nonbonded_ias->maximal_cutoff());
409
410#ifdef COLLISION_DETECTION
411 max_cut = std::max(max_cut, collision_detection->cutoff());
412#endif
413 return max_cut;
414}
415
417 try {
418#ifdef ELECTROSTATICS
419 coulomb.sanity_checks();
420#endif
421#ifdef DIPOLES
422 dipoles.sanity_checks();
423#endif
424 } catch (std::runtime_error const &err) {
425 runtimeErrorMsg() << err.what();
426 return true;
427 }
428 return false;
429}
430
432 auto const max_cut = maximal_cutoff();
433 auto const verlet_skin = cell_structure->get_verlet_skin();
434 /* Consider skin only if there are actually interactions */
435 return (max_cut > 0.) ? max_cut + verlet_skin : INACTIVE_CUTOFF;
436}
437
439 box_geo->set_length(box_l);
440 on_boxl_change();
441}
442
444 // sanity checks
445 integrator_sanity_checks();
446 long_range_interactions_sanity_checks();
447 lb.sanity_checks();
448 ek.sanity_checks();
449
450#ifdef NPT
451 if (propagation->integ_switch == INTEG_METHOD_NPT_ISO) {
452 npt_ensemble_init(propagation->recalc_forces);
453 }
454#endif
455
456 /* Prepare the thermostat */
457 if (reinit_thermo) {
458 thermostat->recalc_prefactors(time_step);
459 reinit_thermo = false;
460 propagation->recalc_forces = true;
461 }
462
464
465#ifdef ADDITIONAL_CHECKS
466 if (!Utils::Mpi::all_compare(::comm_cart, cell_structure->use_verlet_list)) {
467 runtimeErrorMsg() << "Nodes disagree about use of verlet lists.";
468 }
469#ifdef ELECTROSTATICS
470 {
471 auto const &actor = coulomb.impl->solver;
472 if (not Utils::Mpi::all_compare(::comm_cart, static_cast<bool>(actor)) or
473 (actor and not Utils::Mpi::all_compare(::comm_cart, (*actor).index())))
474 runtimeErrorMsg() << "Nodes disagree about Coulomb long-range method";
475 }
476#endif
477#ifdef DIPOLES
478 {
479 auto const &actor = dipoles.impl->solver;
480 if (not Utils::Mpi::all_compare(::comm_cart, static_cast<bool>(actor)) or
481 (actor and not Utils::Mpi::all_compare(::comm_cart, (*actor).index())))
482 runtimeErrorMsg() << "Nodes disagree about dipolar long-range method";
483 }
484#endif
485#endif /* ADDITIONAL_CHECKS */
486
487 on_observable_calc();
488}
489
490/**
491 * @brief Returns the ghost flags required for running pair
492 * kernels for the global state, e.g. the force calculation.
493 * @return Required data parts;
494 */
496 /* Position and Properties are always requested. */
498
499 if (lb.is_solver_set())
500 data_parts |= Cells::DATA_PART_MOMENTUM;
501
502 if (thermostat->thermo_switch & THERMO_DPD)
503 data_parts |= Cells::DATA_PART_MOMENTUM;
504
505 if (thermostat->thermo_switch & THERMO_BOND) {
506 data_parts |= Cells::DATA_PART_MOMENTUM;
507 data_parts |= Cells::DATA_PART_BONDS;
508 }
509
510#ifdef COLLISION_DETECTION
511 if (not collision_detection->is_off()) {
512 data_parts |= Cells::DATA_PART_BONDS;
513 }
514#endif
515
516 return data_parts;
517}
518
519} // namespace System
CellStructureType
Cell structure topology.
@ NSQUARE
Atom decomposition (N-square).
@ HYBRID
Hybrid decomposition.
@ REGULAR
Regular decomposition.
@ INTEG_METHOD_SD
@ INTEG_METHOD_NPT_ISO
@ THERMO_BOND
@ THERMO_DPD
Vector implementation and trait types for boost qvm interoperability.
Data structures for bonded interactions.
Hybrid decomposition cell system.
static LocalBox make_regular_decomposition(Utils::Vector3d const &box_l, Utils::Vector3i const &node_index, Utils::Vector3i const &node_grid)
Definition LocalBox.hpp:69
Main system class.
double get_interaction_range() const
Get the interaction range.
double maximal_cutoff() const
Calculate the maximal cutoff of all interactions.
void on_constraint_change()
Called every time a constraint is changed.
unsigned get_global_ghost_flags() const
Returns the ghost flags required for running pair kernels for the global state, e....
void on_boxl_change(bool skip_method_adaption=false)
Called when the box length has changed.
void set_box_l(Utils::Vector3d const &box_l)
Change the box dimensions.
void set_force_cap(double value)
Set force_cap.
void update_dependent_particles()
Update particles with properties depending on other particles, namely virtual sites and ICC charges.
void on_lb_boundary_conditions_change()
Called when the LB boundary conditions change (geometry, slip velocity, or both).
void veto_boxl_change(bool skip_particle_checks=false) const
void set_time_step(double value)
Set time_step.
void on_particle_change()
Called every time a particle property changes.
bool long_range_interactions_sanity_checks() const
Check electrostatic and magnetostatic methods are properly initialized.
void on_particle_charge_change()
Called every time a particle charge changes.
void on_particle_local_change()
Called every time a particle local property changes.
void on_observable_calc()
called before calculating observables, i.e.
void check_kT(double value) const
Veto temperature change.
static std::shared_ptr< System > create()
void set_min_global_cut(double value)
Set min_global_cut.
void set_cell_structure_topology(CellStructureType topology)
Change cell structure topology.
void rebuild_cell_structure()
Rebuild cell lists.
Communicator communicator
boost::mpi::communicator comm_cart
The communicator.
This file contains the defaults for ESPResSo.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
ICC is a method that allows to take into account the influence of arbitrarily shaped dielectric inter...
@ DATA_PART_MOMENTUM
Particle::m.
@ DATA_PART_PROPERTIES
Particle::p.
@ DATA_PART_BONDS
Particle::bonds.
@ DATA_PART_POSITION
Particle::r.
System & get_system()
static std::shared_ptr< System > instance
void set_system(std::shared_ptr< System > new_instance)
bool all_compare(boost::mpi::communicator const &comm, T const &value)
Compare values on all nodes.
constexpr double INACTIVE_CUTOFF
Cutoff for deactivated interactions.
Exports for the NpT code.
void invalidate_fetch_cache()
Invalidate the fetch cache for get_particle_data.
void clear_particle_node()
Invalidate particle_node.
Particles creation and deletion.
void vs_relative_update_particles(CellStructure &cell_structure, BoxGeometry const &box_geo)
Definition relative.cpp:122
Utils::Vector3i calc_node_index() const
Calculate the node index in the Cartesian topology.
Utils::Vector3i node_grid
Regular decomposition cell system.
Routines to thermalize the center of mass and distance of a particle pair.