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
CellStructure.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 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#pragma once
23
25
26#include "BoxGeometry.hpp"
27#include "LocalBox.hpp"
28#include "Particle.hpp"
29#include "ParticleList.hpp"
30#include "ParticleRange.hpp"
32#include "bond_error.hpp"
33#include "cell_system/Cell.hpp"
35#include "config/config.hpp"
36#include "ghosts.hpp"
37#include "system/Leaf.hpp"
38
39#include <utils/math/sqr.hpp>
40
41#include <boost/container/static_vector.hpp>
42#include <boost/iterator/indirect_iterator.hpp>
43#include <boost/range/algorithm/transform.hpp>
44
45#include <algorithm>
46#include <cassert>
47#include <concepts>
48#include <iterator>
49#include <memory>
50#include <optional>
51#include <set>
52#include <span>
53#include <stdexcept>
54#include <utility>
55#include <vector>
56
57template <typename Callable>
58concept ParticleCallback = requires(Callable c, Particle &p) {
59 { c(p) } -> std::same_as<void>;
60};
61
62namespace Cells {
63enum Resort : unsigned {
66 RESORT_GLOBAL = 2u
67};
68
69/**
70 * @brief Flags to select particle parts for communication.
71 */
72enum DataPart : unsigned {
73 DATA_PART_NONE = 0u, /**< Nothing */
74 DATA_PART_PROPERTIES = 1u, /**< Particle::p */
75 DATA_PART_POSITION = 2u, /**< Particle::r */
76 DATA_PART_MOMENTUM = 8u, /**< Particle::m */
77 DATA_PART_FORCE = 16u, /**< Particle::f */
78#ifdef BOND_CONSTRAINT
79 DATA_PART_RATTLE = 32u, /**< Particle::rattle */
80#endif
81 DATA_PART_BONDS = 64u /**< Particle::bonds */
82};
83} // namespace Cells
84
85/**
86 * @brief Map the data parts flags from cells to those
87 * used internally by the ghost communication.
88 *
89 * @param data_parts data parts flags
90 * @return ghost communication flags
91 */
92unsigned map_data_parts(unsigned data_parts);
93
94namespace Cells {
95inline ParticleRange particles(std::span<Cell *const> cells) {
96 /* Find first non-empty cell */
97 auto first_non_empty = std::ranges::find_if(
98 cells, [](const Cell *c) { return not c->particles().empty(); });
99
100 return {CellParticleIterator(first_non_empty, cells.end()),
101 CellParticleIterator(cells.end())};
102}
103} // namespace Cells
104
105/**
106 * @brief Distance vector and length handed to pair kernels.
107 */
108struct Distance {
110 : vec21(vec21), dist2(vec21.norm2()) {}
111
113 double dist2;
114};
115
116namespace detail {
117// NOLINTNEXTLINE(bugprone-exception-escape)
118struct MinimalImageDistance {
119 BoxGeometry const box;
120
121 Distance operator()(Particle const &p1, Particle const &p2) const {
122 return Distance(box.get_mi_vector(p1.pos(), p2.pos()));
123 }
124};
125
126struct EuclidianDistance {
127 Distance operator()(Particle const &p1, Particle const &p2) const {
128 return Distance(p1.pos() - p2.pos());
129 }
130};
131} // namespace detail
132
133/** Describes a cell structure / cell system. Contains information
134 * about the communication of cell contents (particles, ghosts, ...)
135 * between different nodes and the relation between particle
136 * positions and the cell system. All other properties of the cell
137 * system which are not common between different cell systems have to
138 * be stored in separate structures.
139 */
140struct CellStructure : public System::Leaf<CellStructure> {
141private:
142 /** The local id-to-particle index */
143 std::vector<Particle *> m_particle_index;
144 /** Implementation of the primary particle decomposition */
145 std::unique_ptr<ParticleDecomposition> m_decomposition;
146 /** Active type in m_decomposition */
148 /** One of @ref Cells::Resort, announces the level of resort needed.
149 */
150 unsigned m_resort_particles = Cells::RESORT_NONE;
151 bool m_rebuild_verlet_list = true;
152 std::vector<std::pair<Particle *, Particle *>> m_verlet_list;
153 double m_le_pos_offset_at_last_resort = 0.;
154 /** @brief Verlet list skin. */
155 double m_verlet_skin = 0.;
156 bool m_verlet_skin_set = false;
157 double m_verlet_reuse = 0.;
158
159public:
160 CellStructure(BoxGeometry const &box);
161
162 bool use_verlet_list = true;
163
164 /**
165 * @brief Update local particle index.
166 *
167 * Update the entry for a particle in the local particle
168 * index.
169 *
170 * @param id Entry to update.
171 * @param p Pointer to the particle.
172 */
174 assert(id >= 0);
175 // cppcheck-suppress assertWithSideEffect
176 assert(not p or p->id() == id);
177
178 if (static_cast<unsigned int>(id) >= m_particle_index.size())
179 m_particle_index.resize(static_cast<unsigned int>(id + 1));
180
181 m_particle_index[static_cast<unsigned int>(id)] = p;
182 }
183
184 /**
185 * @brief Update local particle index.
186 *
187 * Update the entry for a particle in the local particle
188 * index.
189 *
190 * @param p Pointer to the particle.
191 */
193 update_particle_index(p.id(), std::addressof(p));
194 }
195
196 /**
197 * @brief Update local particle index.
198 *
199 * @param pl List of particles whose index entries should be updated.
200 */
202 for (auto &p : pl) {
203 update_particle_index(p.id(), std::addressof(p));
204 }
205 }
206
207 /**
208 * @brief Clear the particles index.
209 */
210 void clear_particle_index() { m_particle_index.clear(); }
211
212private:
213 /**
214 * @brief Append a particle to a list and update this
215 * particle index accordingly.
216 * @param pl List to add the particle to.
217 * @param p Particle to add.
218 */
219 Particle &append_indexed_particle(ParticleList &pl, Particle &&p) {
220 /* Check if cell may reallocate, in which case the index
221 * entries for all particles in this cell have to be
222 * updated. */
223 auto const may_reallocate = pl.size() >= pl.capacity();
224 auto &new_part = pl.insert(std::move(p));
225
226 if (may_reallocate)
228 else {
229 update_particle_index(new_part);
230 }
231
232 return new_part;
233 }
234
235public:
236 /**
237 * @brief Get a local particle by id.
238 *
239 * @param id Particle to get.
240 * @return Pointer to particle if it is local,
241 * nullptr otherwise.
242 */
244 assert(id >= 0);
245
246 if (static_cast<unsigned int>(id) >= m_particle_index.size())
247 return nullptr;
248
249 return m_particle_index[static_cast<unsigned int>(id)];
250 }
251
252 /** @overload */
253 const Particle *get_local_particle(int id) const {
254 assert(id >= 0);
255
256 if (static_cast<unsigned int>(id) >= m_particle_index.size())
257 return nullptr;
258
259 return m_particle_index[static_cast<unsigned int>(id)];
260 }
261
262 template <class InputRange, class OutputIterator>
263 void get_local_particles(InputRange ids, OutputIterator out) {
264 std::ranges::transform(ids, out,
265 [this](int id) { return get_local_particle(id); });
266 }
267
268 CellStructureType decomposition_type() const { return m_type; }
269
270 /** Maximal cutoff supported by current cell system. */
272
273 /** Maximal pair range supported by current cell system. */
275
277 return Cells::particles(decomposition().local_cells());
278 }
279
281 return Cells::particles(decomposition().ghost_cells());
282 }
283
284 /**
285 * @brief Run a kernel on all local particles.
286 * The kernel is assumed to be thread-safe.
287 */
288 template <typename Kernel>
290 void for_each_local_particle(Kernel f) const {
291 for (auto &p : local_particles()) {
292 f(p);
293 }
294 }
295
296 /**
297 * @brief Run a kernel on all ghost particles.
298 * The kernel is assumed to be thread-safe.
299 */
300 template <typename Kernel>
302 void for_each_ghost_particle(Kernel f) const {
303 for (auto &p : ghost_particles()) {
304 f(p);
305 }
306 }
307
308private:
309 /** Cell system dependent function to find the right cell for a
310 * particle.
311 * \param p Particle.
312 * \return pointer to cell where to put the particle, nullptr
313 * if the particle does not belong on this node.
314 */
315 Cell *particle_to_cell(const Particle &p) {
317 }
318 Cell const *particle_to_cell(const Particle &p) const {
320 }
321
322public:
323 /**
324 * @brief Add a particle.
325 *
326 * Moves a particle into the cell system. This adds
327 * a particle to the local node, irrespective of where
328 * it belongs.
329 *
330 * @param p Particle to add.
331 * @return Pointer to the particle in the cell
332 * system.
333 */
335
336 /**
337 * @brief Add a particle.
338 *
339 * Moves a particle into the cell system, if it
340 * belongs to this node. Otherwise this does not
341 * have an effect and the particle is discarded.
342 * This can be used to add a particle without
343 * knowledge where it should be placed by calling
344 * the function on all nodes, it will then add
345 * the particle in exactly one place.
346 *
347 * @param p Particle to add.
348 * @return Pointer to particle if it is local, null
349 * otherwise.
350 */
352
353 /**
354 * @brief Remove a particle.
355 *
356 * Removes a particle and all bonds pointing
357 * to it. This is a collective call.
358 *
359 * @param id Id of particle to remove.
360 */
361 void remove_particle(int id);
362
363 /**
364 * @brief Get the maximal particle id on this node.
365 *
366 * This returns the highest particle id on
367 * this node, or -1 if there are no particles on this node.
368 */
369 int get_max_local_particle_id() const;
370
371 /**
372 * @brief Remove all particles from the cell system.
373 *
374 * This allows linear time removal of all particles from
375 * the system, removing each particle individually would
376 * be quadratic.
377 */
379
380 /**
381 * @brief Get the underlying particle decomposition.
382 *
383 * Should be used solely for informative purposes.
384 *
385 * @return The active particle decomposition.
386 */
388 return assert(m_decomposition), *m_decomposition;
389 }
390
391private:
393 return assert(m_decomposition), *m_decomposition;
394 }
395
396public:
397 /**
398 * @brief Increase the local resort level at least to @p level.
399 */
401 m_resort_particles |= level;
402 assert(m_resort_particles >= level);
403 }
404
405 /**
406 * @brief Get the currently scheduled resort level.
407 */
408 unsigned get_resort_particles() const { return m_resort_particles; }
409
410 /**
411 * @brief Set the resort level to sorted.
412 */
413 void clear_resort_particles() { m_resort_particles = Cells::RESORT_NONE; }
414
415 /**
416 * @brief Check whether a particle has moved further than half the skin
417 * since the last Verlet list update, thus requiring a resort.
418 * @param additional_offset Offset which is added to the distance the
419 * particle has travelled when comparing to half
420 * the Verlet skin (e.g., for Lees-Edwards BC).
421 * @return Whether a resort is needed.
422 */
423 bool
424 check_resort_required(Utils::Vector3d const &additional_offset = {}) const {
425 auto const particles = local_particles();
426 auto const lim = Utils::sqr(m_verlet_skin / 2.) - additional_offset.norm2();
427 return std::any_of(
428 particles.begin(), particles.end(), [lim](const auto &p) {
429 return ((p.pos() - p.pos_at_last_verlet_update()).norm2() > lim);
430 });
431 }
432
434 return m_le_pos_offset_at_last_resort;
435 }
436
437 /**
438 * @brief Synchronize number of ghosts.
439 */
440 void ghosts_count();
441
442 /**
443 * @brief Update ghost particles.
444 *
445 * Update ghost particles with data from the real particles.
446 *
447 * @param data_parts Particle parts to update, combination of @ref
448 * Cells::DataPart
449 */
450 void ghosts_update(unsigned data_parts);
451
452 /**
453 * @brief Update ghost particles, with particle resort if needed.
454 *
455 * Update ghost particles with data from the real particles.
456 * Resort particles if a resort is due.
457 *
458 * @param data_parts Particle parts to update, combination of @ref
459 * Cells::DataPart
460 */
461 void update_ghosts_and_resort_particle(unsigned data_parts);
462
463 /**
464 * @brief Add forces from ghost particles to real particles.
465 */
467
468#ifdef BOND_CONSTRAINT
469 /**
470 * @brief Add rattle corrections from ghost particles to real particles.
471 */
473#endif
474
475 /**
476 * @brief Resort particles.
477 */
478 void resort_particles(bool global_flag);
479
480 /** @brief Whether the Verlet skin is set. */
481 auto is_verlet_skin_set() const { return m_verlet_skin_set; }
482
483 /** @brief Get the Verlet skin. */
484 auto get_verlet_skin() const { return m_verlet_skin; }
485
486 /** @brief Set the Verlet skin. */
487 void set_verlet_skin(double value);
488
489 /** @brief Set the Verlet skin using a heuristic. */
491
492 void update_verlet_stats(int n_steps, int n_verlet_updates) {
493 if (n_verlet_updates > 0) {
494 m_verlet_reuse = n_steps / static_cast<double>(n_verlet_updates);
495 } else {
496 m_verlet_reuse = 0.;
497 }
498 }
499
500 /** @brief Average number of integration steps the Verlet list was re-used */
501 auto get_verlet_reuse() const { return m_verlet_reuse; }
502
503 /**
504 * @brief Resolve ids to particles.
505 *
506 * @throws BondResolutionError if one of the ids
507 * was not found.
508 *
509 * @param partner_ids Ids to resolve.
510 * @return Vector of Particle pointers.
511 */
512 auto resolve_bond_partners(std::span<const int> partner_ids) {
513 boost::container::static_vector<Particle *, 4> partners;
514 get_local_particles(partner_ids, std::back_inserter(partners));
515
516 /* Check if id resolution failed for any partner */
517 if (std::ranges::find(partners, nullptr) != partners.end()) {
518 throw BondResolutionError{};
519 }
520
521 return partners;
522 }
523
524private:
525 /**
526 * @brief Execute kernel for every bond on particle.
527 * @tparam Handler Callable, which can be invoked with
528 * (Particle, int, std::span<Particle *>),
529 * returning a bool.
530 * @param p Particles for whom the bonds are evaluated.
531 * @param handler is called for every bond, and handed
532 * p, the bond id and a span with the bond
533 * partners as arguments. Its return value
534 * should indicate if the bond was broken.
535 */
536 template <class Handler>
537 void execute_bond_handler(Particle &p, Handler handler) {
538 for (const BondView bond : p.bonds()) {
539 auto const partner_ids = bond.partner_ids();
540
541 try {
542 auto partners = resolve_bond_partners(partner_ids);
543 auto const partners_span = std::span(partners.data(), partners.size());
544 auto const bond_broken = handler(p, bond.bond_id(), partners_span);
545 if (bond_broken) {
546 bond_broken_error(p.id(), partner_ids);
547 }
548 } catch (const BondResolutionError &) {
549 bond_broken_error(p.id(), partner_ids);
550 }
551 }
552 }
553
554 /**
555 * @brief Go through ghost cells and remove the ghost entries from the
556 * local particle index.
557 */
558 void invalidate_ghosts() {
559 for (auto const &p : ghost_particles()) {
560 if (get_local_particle(p.id()) == &p) {
561 update_particle_index(p.id(), nullptr);
562 }
563 }
564 }
565
566 /** @brief Set the particle decomposition, keeping the particles. */
567 void set_particle_decomposition(
568 std::unique_ptr<ParticleDecomposition> &&decomposition) {
570
571 /* Swap in new cell system */
572 std::swap(m_decomposition, decomposition);
573
574 /* Add particles to new system */
575 for (auto &p : Cells::particles(decomposition->local_cells())) {
576 add_particle(std::move(p));
577 }
578 }
579
580public:
581 /**
582 * @brief Set the particle decomposition to @ref AtomDecomposition.
583 */
585
586 /**
587 * @brief Set the particle decomposition to @ref RegularDecomposition.
588 *
589 * @param range Interaction range.
590 * @param fully_connected_boundary neighbor cell directions for Lees-Edwards.
591 */
593 double range,
594 std::optional<std::pair<int, int>> fully_connected_boundary);
595
596 /**
597 * @brief Set the particle decomposition to @ref HybridDecomposition.
598 *
599 * @param cutoff_regular Interaction cutoff_regular.
600 * @param n_square_types Particle types to put into n_square decomposition.
601 */
602 void set_hybrid_decomposition(double cutoff_regular,
603 std::set<int> n_square_types);
604
605private:
606 /**
607 * @brief Run link_cell algorithm for local cells.
608 *
609 * @tparam Kernel Needs to be callable with (Particle, Particle, Distance).
610 * @param kernel Pair kernel functor.
611 */
612 template <class Kernel> void link_cell(Kernel kernel) {
613 auto const maybe_box = decomposition().minimum_image_distance();
614 auto const local_cells_span = decomposition().local_cells();
615 auto const first = boost::make_indirect_iterator(local_cells_span.begin());
616 auto const last = boost::make_indirect_iterator(local_cells_span.end());
617
618 if (maybe_box) {
620 first, last,
621 [&kernel, df = detail::MinimalImageDistance{decomposition().box()}](
622 Particle &p1, Particle &p2) { kernel(p1, p2, df(p1, p2)); });
623 } else {
624 if (decomposition().box().type() != BoxType::CUBOID) {
625 throw std::runtime_error("Non-cuboid box type is not compatible with a "
626 "particle decomposition that relies on "
627 "EuclideanDistance for distance calculation.");
628 }
630 first, last,
631 [&kernel, df = detail::EuclidianDistance{}](
632 Particle &p1, Particle &p2) { kernel(p1, p2, df(p1, p2)); });
633 }
634 }
635
636 /** Non-bonded pair loop with verlet lists.
637 *
638 * @param pair_kernel Kernel to apply
639 * @param verlet_criterion Filter for verlet lists.
640 */
641 template <class PairKernel, class VerletCriterion>
642 void verlet_list_loop(PairKernel pair_kernel,
643 const VerletCriterion &verlet_criterion) {
644 /* In this case the verlet list update is attached to
645 * the pair kernel, and the verlet list is rebuilt as
646 * we go. */
647 if (m_rebuild_verlet_list) {
648 m_verlet_list.clear();
649
650 link_cell([&](Particle &p1, Particle &p2, Distance const &d) {
651 if (verlet_criterion(p1, p2, d)) {
652 m_verlet_list.emplace_back(&p1, &p2);
653 pair_kernel(p1, p2, d);
654 }
655 });
656
657 m_rebuild_verlet_list = false;
658 } else {
659 auto const maybe_box = decomposition().minimum_image_distance();
660 /* In this case the pair kernel is just run over the verlet list. */
661 if (maybe_box) {
662 auto const distance_function =
663 detail::MinimalImageDistance{decomposition().box()};
664 for (auto &pair : m_verlet_list) {
665 pair_kernel(*pair.first, *pair.second,
666 distance_function(*pair.first, *pair.second));
667 }
668 } else {
669 auto const distance_function = detail::EuclidianDistance{};
670 for (auto &pair : m_verlet_list) {
671 pair_kernel(*pair.first, *pair.second,
672 distance_function(*pair.first, *pair.second));
673 }
674 }
675 }
676 }
677
678public:
679 /** Bonded pair loop.
680 * @param bond_kernel Kernel to apply
681 */
682 template <class BondKernel> void bond_loop(BondKernel const &bond_kernel) {
683 for (auto &p : local_particles()) {
684 execute_bond_handler(p, bond_kernel);
685 }
686 }
687
688 /** Non-bonded pair loop.
689 * @param pair_kernel Kernel to apply
690 */
691 template <class PairKernel> void non_bonded_loop(PairKernel pair_kernel) {
692 link_cell(pair_kernel);
693 }
694
695 /** Non-bonded pair loop with potential use
696 * of verlet lists.
697 * @param pair_kernel Kernel to apply
698 * @param verlet_criterion Filter for verlet lists.
699 */
700 template <class PairKernel, class VerletCriterion>
701 void non_bonded_loop(PairKernel pair_kernel,
702 const VerletCriterion &verlet_criterion) {
703 if (use_verlet_list) {
704 verlet_list_loop(pair_kernel, verlet_criterion);
705 } else {
706 /* No verlet lists, just run the kernel with pairs from the cells. */
707 link_cell(pair_kernel);
708 }
709 }
710
711 /**
712 * @brief Check that particle index is commensurate with particles.
713 *
714 * For each local particles is checked that has a correct entry
715 * in the particles index, and that there are no excess (non-existing)
716 * particles in the index.
717 */
718 void check_particle_index() const;
719
720 /**
721 * @brief Check that particles are in the correct cell.
722 *
723 * This checks for all local particles that the result
724 * of particles_to_cell is the cell the particles is
725 * actually in, e.g. that the particles are sorted according
726 * to particles_to_cell.
727 */
728 void check_particle_sorting() const;
729
730public:
731 /**
732 * @brief Find cell a particle is stored in.
733 *
734 * For local particles, this returns the cell they
735 * are stored in, otherwise nullptr is returned.
736 *
737 * @param p Particle to find cell for
738 * @return Cell for particle or nullptr.
739 */
741 assert(not get_resort_particles());
742
743 if (p.is_ghost()) {
744 return nullptr;
745 }
746
747 return particle_to_cell(p);
748 }
749
750 /**
751 * @brief Run kernel on all particles inside local cell and its neighbors.
752 *
753 * @param p Particle to find cell for
754 * @param kernel Function with signature <tt>double(Particle const&,
755 * Particle const&, Utils::Vector3d const&)</tt>
756 * @return false if cell is not found, otherwise true
757 */
758 template <class Kernel>
760 Kernel &kernel) {
761 auto const cell = find_current_cell(p);
762
763 if (cell == nullptr) {
764 return false;
765 }
766
767 auto const maybe_box = decomposition().minimum_image_distance();
768
769 if (maybe_box) {
770 auto const distance_function =
771 detail::MinimalImageDistance{decomposition().box()};
772 short_range_neighbor_loop(p, cell, kernel, distance_function);
773 } else {
774 auto const distance_function = detail::EuclidianDistance{};
775 short_range_neighbor_loop(p, cell, kernel, distance_function);
776 }
777 return true;
778 }
779
780private:
781 template <class Kernel, class DistanceFunc>
782 void short_range_neighbor_loop(Particle const &p1, Cell *const cell,
783 Kernel &kernel, DistanceFunc const &df) {
784 /* Iterate over particles inside cell */
785 for (auto const &p2 : cell->particles()) {
786 if (p1.id() != p2.id()) {
787 auto const vec = df(p1, p2).vec21;
788 kernel(p1, p2, vec);
789 }
790 }
791 /* Iterate over all neighbors */
792 for (auto const neighbor : cell->neighbors().all()) {
793 /* Iterate over particles in neighbors */
794 if (neighbor != cell) {
795 for (auto const &p2 : neighbor->particles()) {
796 auto const vec = df(p1, p2).vec21;
797 kernel(p1, p2, vec);
798 }
799 }
800 }
801 }
802};
ParticleIterator< std::span< Cell *const >::iterator > CellParticleIterator
CellStructureType
Cell structure topology.
@ NSQUARE
Atom decomposition (N-square).
unsigned map_data_parts(unsigned data_parts)
Map the data parts flags from cells to those used internally by the ghost communication.
void bond_broken_error(int id, std::span< const int > partner_ids)
Immutable view on a bond.
Definition BondList.hpp:44
BoxType type() const
Utils::Vector< T, 3 > get_mi_vector(const Utils::Vector< T, 3 > &a, const Utils::Vector< T, 3 > &b) const
Get the minimum-image vector between two coordinates.
Definition Cell.hpp:96
auto & particles()
Particles.
Definition Cell.hpp:103
A distributed particle decomposition.
virtual Utils::Vector3d max_cutoff() const =0
Maximum supported cutoff.
virtual std::span< Cell *const > local_cells() const =0
Get pointer to local cells.
virtual Cell * particle_to_cell(Particle const &p)=0
Determine which cell a particle id belongs to.
virtual Utils::Vector3d max_range() const =0
Range in which calculations are performed.
virtual std::optional< BoxGeometry > minimum_image_distance() const =0
Return the box geometry needed for distance calculation if minimum image convention should be used ne...
virtual BoxGeometry const & box() const =0
A range of particles.
Abstract class that represents a component of the system.
std::size_t capacity() const
Capacity of the container.
Definition Bag.hpp:104
T & insert(T const &v)
Insert an element into the container.
Definition Bag.hpp:147
std::size_t size() const
Number of elements in the container.
Definition Bag.hpp:90
Returns true if the particles are to be considered for short range interactions.
This file contains the defaults for ESPResSo.
Ghost particles and particle exchange.
void link_cell(CellIterator first, CellIterator last, PairKernel &&pair_kernel)
Iterates over all particles in the cell range, and over all pairs within the cells and with their nei...
Definition link_cell.hpp:32
DataPart
Flags to select particle parts for communication.
@ DATA_PART_MOMENTUM
Particle::m.
@ DATA_PART_FORCE
Particle::f.
@ DATA_PART_PROPERTIES
Particle::p.
@ DATA_PART_BONDS
Particle::bonds.
@ DATA_PART_NONE
Nothing.
@ DATA_PART_RATTLE
Particle::rattle.
@ DATA_PART_POSITION
Particle::r.
ParticleRange particles(std::span< Cell *const > cells)
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
auto constexpr new_part
Exception indicating that a particle id could not be resolved.
Describes a cell structure / cell system.
ParticleRange ghost_particles() const
Particle * get_local_particle(int id)
Get a local particle by id.
void update_particle_index(ParticleList &pl)
Update local particle index.
void check_particle_sorting() const
Check that particles are in the correct cell.
void clear_resort_particles()
Set the resort level to sorted.
Cell * find_current_cell(const Particle &p)
Find cell a particle is stored in.
auto is_verlet_skin_set() const
Whether the Verlet skin is set.
ParticleDecomposition const & decomposition() const
Get the underlying particle decomposition.
void clear_particle_index()
Clear the particles index.
void update_ghosts_and_resort_particle(unsigned data_parts)
Update ghost particles, with particle resort if needed.
Particle * add_local_particle(Particle &&p)
Add a particle.
void set_verlet_skin_heuristic()
Set the Verlet skin using a heuristic.
void set_verlet_skin(double value)
Set the Verlet skin.
void ghosts_update(unsigned data_parts)
Update ghost particles.
auto get_le_pos_offset_at_last_resort() const
void get_local_particles(InputRange ids, OutputIterator out)
void update_verlet_stats(int n_steps, int n_verlet_updates)
void for_each_local_particle(Kernel f) const
Run a kernel on all local particles.
void update_particle_index(int id, Particle *p)
Update local particle index.
void ghosts_reduce_forces()
Add forces from ghost particles to real particles.
unsigned get_resort_particles() const
Get the currently scheduled resort level.
auto get_verlet_reuse() const
Average number of integration steps the Verlet list was re-used.
void non_bonded_loop(PairKernel pair_kernel)
Non-bonded pair loop.
Utils::Vector3d max_range() const
Maximal pair range supported by current cell system.
bool check_resort_required(Utils::Vector3d const &additional_offset={}) const
Check whether a particle has moved further than half the skin since the last Verlet list update,...
const Particle * get_local_particle(int id) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
auto resolve_bond_partners(std::span< const int > partner_ids)
Resolve ids to particles.
void bond_loop(BondKernel const &bond_kernel)
Bonded pair loop.
void ghosts_count()
Synchronize number of ghosts.
void set_resort_particles(Cells::Resort level)
Increase the local resort level at least to level.
void remove_particle(int id)
Remove a particle.
Particle * add_particle(Particle &&p)
Add a particle.
void resort_particles(bool global_flag)
Resort particles.
void check_particle_index() const
Check that particle index is commensurate with particles.
auto get_verlet_skin() const
Get the Verlet skin.
void set_regular_decomposition(double range, std::optional< std::pair< int, int > > fully_connected_boundary)
Set the particle decomposition to RegularDecomposition.
void set_atom_decomposition()
Set the particle decomposition to AtomDecomposition.
bool run_on_particle_short_range_neighbors(Particle const &p, Kernel &kernel)
Run kernel on all particles inside local cell and its neighbors.
void remove_all_particles()
Remove all particles from the cell system.
ParticleRange local_particles() const
void update_particle_index(Particle &p)
Update local particle index.
void for_each_ghost_particle(Kernel f) const
Run a kernel on all ghost particles.
void ghosts_reduce_rattle_correction()
Add rattle corrections from ghost particles to real particles.
CellStructureType decomposition_type() const
void set_hybrid_decomposition(double cutoff_regular, std::set< int > n_square_types)
Set the particle decomposition to HybridDecomposition.
int get_max_local_particle_id() const
Get the maximal particle id on this node.
Utils::Vector3d max_cutoff() const
Maximal cutoff supported by current cell system.
void non_bonded_loop(PairKernel pair_kernel, const VerletCriterion &verlet_criterion)
Non-bonded pair loop with potential use of verlet lists.
Distance vector and length handed to pair kernels.
Utils::Vector3d vec21
Distance(Utils::Vector3d const &vec21)
Struct holding all information for one particle.
Definition Particle.hpp:395
bool is_ghost() const
Definition Particle.hpp:440
auto const & pos() const
Definition Particle.hpp:431
auto const & id() const
Definition Particle.hpp:414