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
integrate.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2023 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/** \file
23 * Molecular dynamics integrator.
24 *
25 * For more information about the integrator
26 * see \ref integrate.hpp "integrate.hpp".
27 */
28
29#include "integrate.hpp"
36
37#include "BoxGeometry.hpp"
38#include "ParticleRange.hpp"
39#include "PropagationMode.hpp"
40#include "accumulators/AutoUpdateAccumulators.hpp"
44#include "cells.hpp"
45#include "collision_detection/CollisionDetection.hpp"
46#include "communication.hpp"
47#include "errorhandling.hpp"
48#include "forces.hpp"
50#include "lb/utils.hpp"
53#include "npt.hpp"
54#include "rattle.hpp"
55#include "rotation.hpp"
56#include "signalhandling.hpp"
57#include "system/System.hpp"
58#include "thermostat.hpp"
62
63#include <boost/mpi/collectives/all_reduce.hpp>
64
65#ifdef CALIPER
66#include <caliper/cali.h>
67#endif
68
69#ifdef VALGRIND
70#include <callgrind.h>
71#endif
72
73#include <algorithm>
74#include <cassert>
75#include <cmath>
76#include <csignal>
77#include <functional>
78#include <limits>
79#include <stdexcept>
80#include <string>
81#include <utility>
82
83#ifdef WALBERLA
84#ifdef WALBERLA_STATIC_ASSERT
85#error "waLberla headers should not be visible to the ESPResSo core"
86#endif
87#endif
88
89namespace {
90volatile std::sig_atomic_t ctrl_C = 0;
91} // namespace
92
93namespace LeesEdwards {
94
95/**
96 * @brief Update the Lees-Edwards parameters of the box geometry
97 * for the current simulation time.
98 */
99void LeesEdwards::update_box_params(BoxGeometry &box_geo, double sim_time) {
100 if (box_geo.type() == BoxType::LEES_EDWARDS) {
101 assert(m_protocol != nullptr);
102 box_geo.lees_edwards_update(get_pos_offset(sim_time, *m_protocol),
103 get_shear_velocity(sim_time, *m_protocol));
104 }
105}
106
107void LeesEdwards::set_protocol(std::shared_ptr<ActiveProtocol> protocol) {
108 auto &system = get_system();
109 auto &cell_structure = *system.cell_structure;
110 auto &box_geo = *system.box_geo;
111 box_geo.set_type(BoxType::LEES_EDWARDS);
112 m_protocol = std::move(protocol);
113 update_box_params(box_geo, system.get_sim_time());
114 system.propagation->recalc_forces = true;
115 cell_structure.set_resort_particles(Cells::RESORT_LOCAL);
116}
117
119 auto &system = get_system();
120 auto &cell_structure = *system.cell_structure;
121 auto &box_geo = *system.box_geo;
122 m_protocol = nullptr;
123 box_geo.set_type(BoxType::CUBOID);
124 system.propagation->recalc_forces = true;
125 cell_structure.set_resort_particles(Cells::RESORT_LOCAL);
126}
127
128} // namespace LeesEdwards
129
131 switch (integ_switch) {
134 break;
135 case INTEG_METHOD_NVT: {
136 // NOLINTNEXTLINE(bugprone-branch-clone)
137 if ((thermo_switch & THERMO_LB) and (thermo_switch & THERMO_LANGEVIN)) {
139#ifdef ROTATION
141#endif
142 } else if (thermo_switch & THERMO_LB) {
144#ifdef ROTATION
146#endif
147 } else if (thermo_switch & THERMO_LANGEVIN) {
149#ifdef ROTATION
151#endif
152 } else {
154#ifdef ROTATION
156#endif
157 }
158 break;
159 }
160#ifdef NPT
163 break;
164#endif
165 case INTEG_METHOD_BD:
167#ifdef ROTATION
169#endif
170 break;
171#ifdef STOKESIAN_DYNAMICS
172 case INTEG_METHOD_SD:
174 break;
175#endif // STOKESIAN_DYNAMICS
176 default:
177 throw std::runtime_error("Unknown value for integ_switch");
178 }
179}
180
182 int used_propagations = PropagationMode::NONE;
183 for (auto &p : cell_structure->local_particles()) {
184 used_propagations |= p.propagation();
185 }
186 if (used_propagations & PropagationMode::SYSTEM_DEFAULT) {
187 used_propagations |= propagation->default_propagation;
188 }
189 used_propagations = boost::mpi::all_reduce(::comm_cart, used_propagations,
190 std::bit_or<int>());
191 propagation->used_propagations = used_propagations;
192}
193
194void System::System::integrator_sanity_checks() const {
195 auto const thermo_switch = thermostat->thermo_switch;
196 if (time_step <= 0.) {
197 runtimeErrorMsg() << "time_step not set";
198 }
199 if (propagation->integ_switch == INTEG_METHOD_STEEPEST_DESCENT) {
200 if (thermo_switch != THERMO_OFF) {
202 << "The steepest descent integrator is incompatible with thermostats";
203 }
204 }
205 if (propagation->integ_switch == INTEG_METHOD_NVT) {
206 if (thermo_switch & (THERMO_NPT_ISO | THERMO_BROWNIAN | THERMO_SD)) {
207 runtimeErrorMsg() << "The VV integrator is incompatible with the "
208 "currently active combination of thermostats";
209 }
210 }
211#ifdef NPT
212 if (propagation->used_propagations & PropagationMode::TRANS_LANGEVIN_NPT) {
213 if (thermo_switch != THERMO_NPT_ISO) {
214 runtimeErrorMsg() << "The NpT integrator requires the NpT thermostat";
215 }
216 if (box_geo->type() == BoxType::LEES_EDWARDS) {
217 runtimeErrorMsg() << "The NpT integrator cannot use Lees-Edwards";
218 }
219 try {
220 nptiso->coulomb_dipole_sanity_checks(*this);
221 } catch (std::runtime_error const &err) {
222 runtimeErrorMsg() << err.what();
223 }
224 }
225#endif
226 if (propagation->used_propagations & PropagationMode::TRANS_BROWNIAN) {
227 if (thermo_switch != THERMO_BROWNIAN) {
228 runtimeErrorMsg() << "The BD integrator requires the BD thermostat";
229 }
230 }
231 if (propagation->used_propagations & PropagationMode::TRANS_STOKESIAN) {
232#ifdef STOKESIAN_DYNAMICS
233 if (thermo_switch != THERMO_SD) {
234 runtimeErrorMsg() << "The SD integrator requires the SD thermostat";
235 }
236#endif
237 }
238 if (lb.is_solver_set() and (propagation->used_propagations &
241 if (thermostat->lb == nullptr) {
242 runtimeErrorMsg() << "The LB integrator requires the LB thermostat";
243 }
244 }
245 if (bonded_ias->get_n_thermalized_bonds() >= 1 and
246 (thermostat->thermalized_bond == nullptr or
247 (thermo_switch & THERMO_BOND) == 0)) {
249 << "Thermalized bonds require the thermalized_bond thermostat";
250 }
251
252#ifdef ROTATION
253 for (auto const &p : cell_structure->local_particles()) {
254 using namespace PropagationMode;
255 if (p.can_rotate() and not p.is_virtual() and
256 (p.propagation() & (SYSTEM_DEFAULT | ROT_EULER | ROT_LANGEVIN |
257 ROT_BROWNIAN | ROT_STOKESIAN)) == 0) {
259 << "Rotating particles must have a rotation propagation mode enabled";
260 break;
261 }
262 }
263#endif
264}
265
266#ifdef WALBERLA
267void walberla_tau_sanity_checks(std::string method, double tau,
268 double time_step) {
269 if (time_step <= 0.) {
270 return;
271 }
272 // use float epsilon since tau may be a float
273 auto const eps = static_cast<double>(std::numeric_limits<float>::epsilon());
274 if ((tau - time_step) / (tau + time_step) < -eps)
275 throw std::invalid_argument(method + " tau (" + std::to_string(tau) +
276 ") must be >= MD time_step (" +
277 std::to_string(time_step) + ")");
278 auto const factor = tau / time_step;
279 if (std::fabs(std::round(factor) - factor) / factor > eps)
280 throw std::invalid_argument(method + " tau (" + std::to_string(tau) +
281 ") must be an integer multiple of the "
282 "MD time_step (" +
283 std::to_string(time_step) + "). Factor is " +
284 std::to_string(factor));
285}
286
287void walberla_agrid_sanity_checks(std::string method,
288 Utils::Vector3d const &geo_left,
289 Utils::Vector3d const &geo_right,
290 Utils::Vector3d const &lattice_left,
291 Utils::Vector3d const &lattice_right,
292 double agrid) {
293 // waLBerla and ESPResSo must agree on domain decomposition
294 auto const tol = agrid / 1E6;
295 if ((lattice_left - geo_left).norm2() > tol or
296 (lattice_right - geo_right).norm2() > tol) {
297 runtimeErrorMsg() << "\nMPI rank " << ::this_node << ": "
298 << "left ESPResSo: [" << geo_left << "], "
299 << "left waLBerla: [" << lattice_left << "]"
300 << "\nMPI rank " << ::this_node << ": "
301 << "right ESPResSo: [" << geo_right << "], "
302 << "right waLBerla: [" << lattice_right << "]"
303 << "\nfor method: " << method;
304 throw std::runtime_error(
305 "waLBerla and ESPResSo disagree about domain decomposition.");
306 }
307}
308#endif // WALBERLA
309
311 auto &cell_structure = *system.cell_structure;
312 auto const offset = LeesEdwards::verlet_list_offset(
313 *system.box_geo, cell_structure.get_le_pos_offset_at_last_resort());
314 if (cell_structure.check_resort_required(offset)) {
315 cell_structure.set_resort_particles(Cells::RESORT_LOCAL);
316 }
317}
318
320 auto const &propagation = *this->propagation;
321 if ((not thermostat->langevin) or ((propagation.used_propagations &
324 return;
325 }
326 auto const &langevin = *thermostat->langevin;
327 auto const kT = thermostat->kT;
328 cell_structure->for_each_local_particle([&](Particle &p) {
329 if (propagation.should_propagate_with(p, PropagationMode::TRANS_LANGEVIN))
330 p.force() += friction_thermo_langevin(langevin, p, time_step, kT);
331#ifdef ROTATION
332 if (propagation.should_propagate_with(p, PropagationMode::ROT_LANGEVIN))
334 p, friction_thermo_langevin_rotation(langevin, p, time_step, kT));
335#endif
336 });
337}
338
339/** @brief Calls the hook for propagation kernels before the force calculation
340 * @return whether or not to stop the integration loop early.
341 */
342static bool integrator_step_1(CellStructure &cell_structure,
343 Propagation const &propagation,
344 System::System &system, double time_step) {
345 // steepest decent
347 return steepest_descent_step(cell_structure.local_particles());
348
349 auto const &thermostat = *system.thermostat;
350 auto const kT = thermostat.kT;
351 cell_structure.for_each_local_particle([&](Particle &p) {
352#ifdef VIRTUAL_SITES
353 // virtual sites are updated later in the integration loop
354 if (p.is_virtual())
355 return;
356#endif
357 if (propagation.should_propagate_with(
359 velocity_verlet_propagator_1(p, time_step);
361 velocity_verlet_propagator_1(p, time_step);
362#ifdef ROTATION
364 velocity_verlet_rotator_1(p, time_step);
365#endif
367 velocity_verlet_propagator_1(p, time_step);
368#ifdef ROTATION
370 velocity_verlet_rotator_1(p, time_step);
371#endif
373 brownian_dynamics_propagator(*thermostat.brownian, p, time_step, kT);
374#ifdef ROTATION
376 brownian_dynamics_rotator(*thermostat.brownian, p, time_step, kT);
377#endif
378 });
379
380#ifdef NPT
383 auto pred = PropagationPredicateNPT(propagation.default_propagation);
385 *thermostat.npt_iso, time_step, system);
386 }
387#endif
388
389#ifdef STOKESIAN_DYNAMICS
392 auto pred = PropagationPredicateStokesian(propagation.default_propagation);
393 stokesian_dynamics_step_1(cell_structure.local_particles().filter(pred),
394 *thermostat.stokesian, time_step, kT);
395 }
396#endif // STOKESIAN_DYNAMICS
397
398 return false;
399}
400
401static void integrator_step_2(CellStructure &cell_structure,
402 Propagation const &propagation,
403 [[maybe_unused]] System::System &system,
404 double time_step) {
406 return;
407
408 cell_structure.for_each_local_particle([&](Particle &p) {
409#ifdef VIRTUAL_SITES
410 // virtual sites are updated later in the integration loop
411 if (p.is_virtual())
412 return;
413#endif
414 if (propagation.should_propagate_with(
416 velocity_verlet_propagator_2(p, time_step);
418 velocity_verlet_propagator_2(p, time_step);
419#ifdef ROTATION
421 velocity_verlet_rotator_2(p, time_step);
422#endif
424 velocity_verlet_propagator_2(p, time_step);
425#ifdef ROTATION
427 velocity_verlet_rotator_2(p, time_step);
428#endif
429 });
430
431#ifdef NPT
434 auto pred = PropagationPredicateNPT(propagation.default_propagation);
436 time_step, system);
437 }
438#endif
439}
440
441int System::System::integrate(int n_steps, int reuse_forces) {
442#ifdef CALIPER
443 CALI_CXX_MARK_FUNCTION;
444#endif
445 auto &propagation = *this->propagation;
446#ifdef VIRTUAL_SITES_RELATIVE
447 auto const has_vs_rel = [&propagation]() {
448 return propagation.used_propagations & (PropagationMode::ROT_VS_RELATIVE |
450 };
451#endif
452#ifdef BOND_CONSTRAINT
453 auto const n_rigid_bonds = bonded_ias->get_n_rigid_bonds();
454#endif
455
456 // Prepare particle structure and run sanity checks of all active algorithms
457 propagation.update_default_propagation(thermostat->thermo_switch);
458 update_used_propagations();
459 on_integration_start();
460
461 // If any method vetoes (e.g. P3M not initialized), immediately bail out
463 return INTEG_ERROR_RUNTIME;
464
465 // Additional preparations for the first integration step
466 if (reuse_forces == INTEG_REUSE_FORCES_NEVER or
467 ((reuse_forces != INTEG_REUSE_FORCES_ALWAYS) and
468 propagation.recalc_forces)) {
469#ifdef CALIPER
470 CALI_MARK_BEGIN("Initial Force Calculation");
471#endif
472 thermostat->lb_coupling_deactivate();
473
474#ifdef VIRTUAL_SITES_RELATIVE
475 if (has_vs_rel()) {
476 vs_relative_update_particles(*cell_structure, *box_geo);
477 }
478#endif
479
480 // Communication step: distribute ghost positions
481 cell_structure->update_ghosts_and_resort_particle(get_global_ghost_flags());
482
483 calculate_forces();
484
485 if (propagation.integ_switch != INTEG_METHOD_STEEPEST_DESCENT) {
486#ifdef ROTATION
487 convert_initial_torques(cell_structure->local_particles());
488#endif
489 }
490
491#ifdef CALIPER
492 CALI_MARK_END("Initial Force Calculation");
493#endif
494 }
495
496 thermostat->lb_coupling_activate();
497
499 return INTEG_ERROR_RUNTIME;
500
501 // Keep track of the number of Verlet updates (i.e. particle resorts)
502 int n_verlet_updates = 0;
503
504 // Keep track of whether an interrupt signal was caught (only in singleton
505 // mode, since signal handlers are unreliable with more than 1 MPI rank)
506 auto const singleton_mode = comm_cart.size() == 1;
507 auto caught_sigint = false;
508 auto caught_error = false;
509
510 auto lb_active = false;
511 auto ek_active = false;
512 if (propagation.integ_switch != INTEG_METHOD_STEEPEST_DESCENT) {
513 lb_active = lb.is_solver_set();
514 ek_active = ek.is_ready_for_propagation();
515 }
516 auto const calc_md_steps_per_tau = [this](double tau) {
517 return static_cast<int>(std::round(tau / time_step));
518 };
519
520#ifdef VALGRIND
521 CALLGRIND_START_INSTRUMENTATION;
522#endif
523 // Integration loop
524#ifdef CALIPER
525 CALI_CXX_MARK_LOOP_BEGIN(integration_loop, "Integration loop");
526#endif
527 int integrated_steps = 0;
528 for (int step = 0; step < n_steps; step++) {
529#ifdef CALIPER
530 CALI_CXX_MARK_LOOP_ITERATION(integration_loop, step);
531#endif
532
533#ifdef BOND_CONSTRAINT
534 if (n_rigid_bonds)
535 save_old_position(cell_structure->local_particles(),
536 cell_structure->ghost_particles());
537#endif
538
539 lees_edwards->update_box_params(*box_geo, sim_time);
540 bool early_exit =
541 integrator_step_1(*cell_structure, propagation, *this, time_step);
542 if (early_exit)
543 break;
544
545 sim_time += time_step;
546 if (box_geo->type() == BoxType::LEES_EDWARDS) {
547 auto const kernel = LeesEdwards::Push{*box_geo};
548 cell_structure->for_each_local_particle(
549 [&kernel](Particle &p) { kernel(p); });
550 }
551
552#ifdef NPT
553 if (propagation.integ_switch != INTEG_METHOD_NPT_ISO)
554#endif
555 {
557 }
558
559 // Propagate philox RNG counters
560 thermostat->philox_counter_increment();
561
562#ifdef BOND_CONSTRAINT
563 // Correct particle positions that participate in a rigid/constrained bond
564 if (n_rigid_bonds) {
565 correct_position_shake(*cell_structure, *box_geo, *bonded_ias);
566 }
567#endif
568
569#ifdef VIRTUAL_SITES_RELATIVE
570 if (has_vs_rel()) {
571#ifdef NPT
572 if (propagation.integ_switch == INTEG_METHOD_NPT_ISO) {
573 cell_structure->update_ghosts_and_resort_particle(
575 }
576#endif // NPT
577 vs_relative_update_particles(*cell_structure, *box_geo);
578 }
579#endif // VIRTUAL_SITES_RELATIVE
580
581 if (cell_structure->get_resort_particles() >= Cells::RESORT_LOCAL)
582 n_verlet_updates++;
583
584 // Communication step: distribute ghost positions
585 cell_structure->update_ghosts_and_resort_particle(get_global_ghost_flags());
586
587 calculate_forces();
588
589#ifdef VIRTUAL_SITES_INERTIALESS_TRACERS
590 if (thermostat->lb and
591 (propagation.used_propagations & PropagationMode::TRANS_LB_TRACER)) {
592 lb_tracers_add_particle_force_to_fluid(*cell_structure, *box_geo,
593 *local_geo, lb);
594 }
595#endif
596 integrator_step_2(*cell_structure, propagation, *this, time_step);
597 if (propagation.integ_switch == INTEG_METHOD_BD) {
599 }
600 if (box_geo->type() == BoxType::LEES_EDWARDS) {
601 auto const kernel = LeesEdwards::UpdateOffset{*box_geo};
602 cell_structure->for_each_local_particle(
603 [&kernel](Particle &p) { kernel(p); });
604 }
605#ifdef BOND_CONSTRAINT
606 if (n_rigid_bonds) {
607 correct_velocity_shake(*cell_structure, *box_geo, *bonded_ias);
608 }
609#endif
610
611 // propagate one-step functionalities
612 if (propagation.integ_switch != INTEG_METHOD_STEEPEST_DESCENT) {
613 if (lb_active and ek_active) {
614 // assume that they are coupled, which is not necessarily true
615 auto const md_steps_per_lb_step = calc_md_steps_per_tau(lb.get_tau());
616 auto const md_steps_per_ek_step = calc_md_steps_per_tau(ek.get_tau());
617
618 if (md_steps_per_lb_step != md_steps_per_ek_step) {
620 << "LB and EK are active but with different time steps.";
621 }
622
623 assert(not lb.is_gpu());
624 assert(propagation.lb_skipped_md_steps ==
625 propagation.ek_skipped_md_steps);
626
627 propagation.lb_skipped_md_steps += 1;
628 propagation.ek_skipped_md_steps += 1;
629 if (propagation.lb_skipped_md_steps >= md_steps_per_lb_step) {
630 propagation.lb_skipped_md_steps = 0;
631 propagation.ek_skipped_md_steps = 0;
632 lb.propagate();
633 lb.ghost_communication_vel();
634 ek.propagate();
635 }
636 } else if (lb_active) {
637 auto const md_steps_per_lb_step = calc_md_steps_per_tau(lb.get_tau());
638 propagation.lb_skipped_md_steps += 1;
639 if (propagation.lb_skipped_md_steps >= md_steps_per_lb_step) {
640 propagation.lb_skipped_md_steps = 0;
641 lb.propagate();
642 }
643 } else if (ek_active) {
644 auto const md_steps_per_ek_step = calc_md_steps_per_tau(ek.get_tau());
645 propagation.ek_skipped_md_steps += 1;
646 if (propagation.ek_skipped_md_steps >= md_steps_per_ek_step) {
647 propagation.ek_skipped_md_steps = 0;
648 ek.propagate();
649 }
650 }
651 if (lb_active and (propagation.used_propagations &
653 thermostat->lb->rng_increment();
654 }
655
656#ifdef VIRTUAL_SITES_INERTIALESS_TRACERS
657 if (thermostat->lb and
658 (propagation.used_propagations & PropagationMode::TRANS_LB_TRACER)) {
659 if (lb_active) {
660 lb.ghost_communication_vel();
661 }
662 lb_tracers_propagate(*cell_structure, lb, time_step);
663 }
664#endif
665
666#ifdef COLLISION_DETECTION
667 collision_detection->handle_collisions();
668#endif
669 bond_breakage->process_queue(*this);
670 }
671
672 integrated_steps++;
673
675 caught_error = true;
676 break;
677 }
678
679 // Check if SIGINT has been caught.
680 if (singleton_mode and ctrl_C == 1) {
681 caught_sigint = true;
682 break;
683 }
684
685 } // for-loop over integration steps
686 if (lb_active) {
687 lb.ghost_communication();
688 }
689 lees_edwards->update_box_params(*box_geo, sim_time);
690#ifdef CALIPER
691 CALI_CXX_MARK_LOOP_END(integration_loop);
692#endif
693
694#ifdef VALGRIND
695 CALLGRIND_STOP_INSTRUMENTATION;
696#endif
697
698#ifdef VIRTUAL_SITES_RELATIVE
699 if (has_vs_rel()) {
700 vs_relative_update_particles(*cell_structure, *box_geo);
701 }
702#endif
703
704 // Verlet list statistics
705 cell_structure->update_verlet_stats(n_steps, n_verlet_updates);
706
707#ifdef NPT
708 if (propagation.integ_switch == INTEG_METHOD_NPT_ISO) {
709 synchronize_npt_state();
710 }
711#endif
712 if (caught_sigint) {
713 ctrl_C = 0;
714 return INTEG_ERROR_SIGINT;
715 }
716 if (caught_error) {
717 return INTEG_ERROR_RUNTIME;
718 }
719 return integrated_steps;
720}
721
722int System::System::integrate_with_signal_handler(int n_steps, int reuse_forces,
723 bool update_accumulators) {
724 assert(n_steps >= 0);
725
726 // Override the signal handler so that the integrator obeys Ctrl+C
727 SignalHandler sa(SIGINT, [](int) { ctrl_C = 1; });
728
729 /* if skin wasn't set, do an educated guess now */
730 if (not cell_structure->is_verlet_skin_set()) {
731 try {
732 cell_structure->set_verlet_skin_heuristic();
733 } catch (...) {
734 if (comm_cart.rank() == 0) {
735 throw;
736 }
737 return INTEG_ERROR_RUNTIME;
738 }
739 }
740
741 if (not update_accumulators or n_steps == 0) {
742 return integrate(n_steps, reuse_forces);
743 }
744
745 for (int i = 0; i < n_steps;) {
746 /* Integrate to either the next accumulator update, or the
747 * end, depending on what comes first. */
748 auto const steps =
749 std::min((n_steps - i), auto_update_accumulators->next_update());
750
751 auto const local_retval = integrate(steps, reuse_forces);
752
753 // make sure all ranks exit when one rank fails
754 std::remove_const_t<decltype(local_retval)> global_retval;
755 boost::mpi::all_reduce(comm_cart, local_retval, global_retval,
756 std::plus<int>());
757 if (global_retval < 0) {
758 return global_retval; // propagate error code
759 }
760
761 reuse_forces = INTEG_REUSE_FORCES_ALWAYS;
762
763 (*auto_update_accumulators)(comm_cart, steps);
764
765 i += steps;
766 }
767
768 return 0;
769}
770
772 sim_time = value;
773 propagation->recalc_forces = true;
774 lees_edwards->update_box_params(*box_geo, sim_time);
775}
@ LEES_EDWARDS
@ INTEG_METHOD_SD
@ INTEG_METHOD_NPT_ISO
@ INTEG_METHOD_STEEPEST_DESCENT
@ INTEG_METHOD_NVT
@ INTEG_METHOD_BD
@ THERMO_SD
@ THERMO_BROWNIAN
@ THERMO_BOND
@ THERMO_LB
@ THERMO_LANGEVIN
@ THERMO_NPT_ISO
@ THERMO_OFF
Data structures for bonded interactions.
This file contains everything related to the global cell structure / cell system.
void lees_edwards_update(double pos_offset, double shear_velocity)
Update the Lees-Edwards parameters of the box geometry for the current simulation time.
BoxType type() const
void update_box_params(BoxGeometry &box_geo, double sim_time)
Update the Lees-Edwards parameters of the box geometry for the current simulation time.
Definition integrate.cpp:99
void set_protocol(std::shared_ptr< ActiveProtocol > protocol)
Set a new Lees-Edwards protocol.
void unset_protocol()
Delete the currently active Lees-Edwards protocol.
ParticleRangeFiltered< Predicate > filter(Predicate pred) const
int default_propagation
void update_default_propagation(int thermo_switch)
bool should_propagate_with(Particle const &p, int mode) const
int used_propagations
RAII guard for signal handling.
Main system class.
void thermostat_force_init()
Calculate initial particle forces from active thermostats.
void update_used_propagations()
Update the global propagation bitmask.
void set_sim_time(double value)
Set sim_time.
int integrate_with_signal_handler(int n_steps, int reuse_forces, bool update_accumulators)
int integrate(int n_steps, int reuse_forces)
Integrate equations of motion.
std::shared_ptr< Thermostat::Thermostat > thermostat
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
int check_runtime_errors(boost::mpi::communicator const &comm)
Count runtime errors on all nodes.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
Force calculation.
static bool integrator_step_1(CellStructure &cell_structure, Propagation const &propagation, System::System &system, double time_step)
Calls the hook for propagation kernels before the force calculation.
static void resort_particles_if_needed(System::System &system)
static void integrator_step_2(CellStructure &cell_structure, Propagation const &propagation, System::System &system, double time_step)
void walberla_agrid_sanity_checks(std::string method, Utils::Vector3d const &geo_left, Utils::Vector3d const &geo_right, Utils::Vector3d const &lattice_left, Utils::Vector3d const &lattice_right, double agrid)
void walberla_tau_sanity_checks(std::string method, double tau, double time_step)
Molecular dynamics integrator.
#define INTEG_ERROR_RUNTIME
Definition integrate.hpp:42
#define INTEG_ERROR_SIGINT
Definition integrate.hpp:43
#define INTEG_REUSE_FORCES_NEVER
recalculate forces unconditionally (mostly used for timing)
Definition integrate.hpp:49
#define INTEG_REUSE_FORCES_ALWAYS
do not recalculate forces (mostly when reading checkpoints with forces)
Definition integrate.hpp:53
void brownian_dynamics_rotator(BrownianThermostat const &brownian, Particle &p, double time_step, double kT)
void brownian_dynamics_propagator(BrownianThermostat const &brownian, Particle &p, double time_step, double kT)
Utils::Vector3d friction_thermo_langevin(LangevinThermostat const &langevin, Particle const &p, double time_step, double kT)
Langevin thermostat for particle translational velocities.
Utils::Vector3d friction_thermo_langevin_rotation(LangevinThermostat const &langevin, Particle const &p, double time_step, double kT)
Langevin thermostat for particle angular velocities.
void lb_tracers_propagate(CellStructure &cell_structure, LB::Solver const &lb, double time_step)
void lb_tracers_add_particle_force_to_fluid(CellStructure &cell_structure, BoxGeometry const &box_geo, LocalBox const &local_box, LB::Solver &lb)
@ DATA_PART_PROPERTIES
Particle::p.
Utils::Vector3d verlet_list_offset(BoxGeometry const &box, double pos_offset_at_last_resort)
double get_shear_velocity(double time, ActiveProtocol const &protocol)
Calculation of current velocity.
double get_pos_offset(double time, ActiveProtocol const &protocol)
Definition protocols.hpp:88
volatile std::sig_atomic_t ctrl_C
Definition integrate.cpp:90
Various procedures concerning interactions between particles.
Exports for the NpT code.
void correct_velocity_shake(CellStructure &cs, BoxGeometry const &box_geo, BondedInteractionsMap const &bonded_ias)
Correction of current velocities using RATTLE algorithm.
Definition rattle.cpp:228
void save_old_position(const ParticleRange &particles, const ParticleRange &ghost_particles)
copy current position
Definition rattle.cpp:55
void correct_position_shake(CellStructure &cs, BoxGeometry const &box_geo, BondedInteractionsMap const &bonded_ias)
Propagate velocity and position while using SHAKE algorithm for bond constraint.
Definition rattle.cpp:153
RATTLE algorithm ().
void vs_relative_update_particles(CellStructure &cell_structure, BoxGeometry const &box_geo)
Definition relative.cpp:122
void convert_initial_torques(const ParticleRange &particles)
Convert torques to the body-fixed frame before the integration loop.
Definition rotation.cpp:188
This file contains all subroutines required to process rotational motion.
Utils::Vector3d convert_vector_body_to_space(const Particle &p, const Utils::Vector3d &vec)
Definition rotation.hpp:57
bool steepest_descent_step(const ParticleRange &particles)
Steepest descent integrator.
void stokesian_dynamics_step_1(ParticleRangeStokesian const &particles, StokesianThermostat const &stokesian, double time_step, double kT)
Describes a cell structure / cell system.
void for_each_local_particle(Kernel f) const
Run a kernel on all local particles.
ParticleRange local_particles() const
Struct holding all information for one particle.
Definition Particle.hpp:395
auto is_virtual() const
Definition Particle.hpp:518
auto const & torque() const
Definition Particle.hpp:479
auto const & force() const
Definition Particle.hpp:435
void velocity_verlet_rotator_1(Particle &p, double time_step)
void velocity_verlet_propagator_2(Particle &p, double time_step)
Final integration step of the Velocity Verlet integrator.
void velocity_verlet_propagator_1(Particle &p, double time_step)
Propagate the velocities and positions.
void velocity_verlet_rotator_2(Particle &p, double time_step)
void velocity_verlet_npt_step_1(ParticleRangeNPT const &particles, IsotropicNptThermostat const &npt_iso, double time_step, System::System &system)
Special propagator for NpT isotropic.
void velocity_verlet_npt_step_2(ParticleRangeNPT const &particles, double time_step, System::System &system)
Final integration step of the Velocity Verlet+NpT integrator.