ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
AtomDecomposition.cpp
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
23
24#include "cell_system/Cell.hpp"
25
26#include <utils/Vector.hpp>
27
28#include <boost/mpi/collectives/all_to_all.hpp>
29
30#include <cstddef>
31#include <limits>
32#include <utility>
33#include <vector>
34
35void AtomDecomposition::configure_neighbors() {
36 std::vector<Cell *> red_neighbors;
37 std::vector<Cell *> black_neighbors;
38
39 /* distribute force calculation work */
40 for (int n = 0; n < m_comm.size(); n++) {
41 if (m_comm.rank() == n) {
42 continue;
43 }
44
45 if (n < m_comm.rank()) {
46 red_neighbors.push_back(&cells.at(n));
47 } else {
48 black_neighbors.push_back(&cells.at(n));
49 }
50 }
51
52 local().m_neighbors = Neighbors<Cell *>(red_neighbors, black_neighbors);
53}
54
55GhostCommunicator AtomDecomposition::prepare_comm() {
56 /* no need for comm for only 1 node */
57 if (m_comm.size() == 1) {
58 return GhostCommunicator{m_comm, 0};
59 }
60
61 auto ghost_comm =
62 GhostCommunicator{m_comm, static_cast<std::size_t>(m_comm.size())};
63 /* every node has its dedicated comm step */
64 for (int n = 0; n < m_comm.size(); n++) {
65 ghost_comm.communications[n].part_lists.resize(1);
66 ghost_comm.communications[n].part_lists[0] = &(cells.at(n).particles());
67 ghost_comm.communications[n].node = n;
68 }
69
70 return ghost_comm;
71}
72
73void AtomDecomposition::configure_comms() {
74 m_exchange_ghosts_comm = prepare_comm();
75 m_collect_ghost_force_comm = prepare_comm();
76
77 if (m_comm.size() > 1) {
78 for (int n = 0; n < m_comm.size(); n++) {
79 /* use the prefetched send buffers. Node 0 transmits first and never
80 * prefetches. */
81 if (m_comm.rank() == 0 || m_comm.rank() != n) {
82 m_exchange_ghosts_comm.communications[n].type = GHOST_BCST;
83 } else {
84 m_exchange_ghosts_comm.communications[n].type =
86 }
87 m_collect_ghost_force_comm.communications[n].type = GHOST_RDCE;
88 }
89 /* first round: all nodes except the first one prefetch their send data */
90 if (m_comm.rank() != 0) {
91 m_exchange_ghosts_comm.communications[0].type |= GHOST_PREFETCH;
92 }
93 }
94}
95
96void AtomDecomposition::mark_cells() {
97 m_local_cells.resize(1, std::addressof(local()));
98 m_ghost_cells.clear();
99 for (int n = 0; n < m_comm.size(); n++) {
100 if (n != m_comm.rank()) {
101 m_ghost_cells.push_back(std::addressof(cells.at(n)));
102 }
103 }
104}
105
106void AtomDecomposition::resort(bool global_flag,
107 std::vector<ParticleChange> &diff) {
108 for (auto &p : local().particles()) {
109 m_box.fold_position(p.pos(), p.image_box());
110
111 p.pos_at_last_verlet_update() = p.pos();
112 }
113
114 /* Local updates are a NoOp for this decomposition. */
115 if (not global_flag) {
116 return;
117 }
118
119 /* Sort displaced particles by the node they belong to. */
120 std::vector<std::vector<Particle>> send_buf(m_comm.size());
121 for (auto it = local().particles().begin();
122 it != local().particles().end();) {
123 auto const target_node = id_to_rank(it->id());
124 if (target_node != m_comm.rank()) {
125 diff.emplace_back(RemovedParticle{it->id()});
126 send_buf.at(target_node).emplace_back(std::move(*it));
127 it = local().particles().erase(it);
128 } else {
129 ++it;
130 }
131 }
132
133 /* Exchange particles */
134 std::vector<std::vector<Particle>> recv_buf(m_comm.size());
135 boost::mpi::all_to_all(m_comm, send_buf, recv_buf);
136
137 diff.emplace_back(ModifiedList{local().particles()});
138
139 /* Add new particles belonging to this node */
140 for (auto &parts : recv_buf) {
141 for (auto &p : parts) {
142 local().particles().insert(std::move(p));
143 }
144 }
145}
146
148 : m_box(box_geo) {}
149
150AtomDecomposition::AtomDecomposition(boost::mpi::communicator comm,
151 BoxGeometry const &box_geo)
152 : m_comm(std::move(comm)), cells(m_comm.size()), m_box(box_geo) {
153 /* create communicators */
154 configure_comms();
155 /* configure neighbor relations */
156 configure_neighbors();
157 /* fill local and ghost cell lists */
158 mark_cells();
159}
160
162 return Utils::Vector3d::broadcast(std::numeric_limits<double>::infinity());
163}
164
Vector implementation and trait types for boost qvm interoperability.
Utils::Vector3d max_range() const override
AtomDecomposition(BoxGeometry const &m_box)
Utils::Vector3d max_cutoff() const override
void resort(bool global_flag, std::vector< ParticleChange > &diff) override
void fold_position(Utils::Vector3d &pos, Utils::Vector3i &image_box) const
Fold coordinates to primary simulation box in-place.
neighbors_type m_neighbors
Definition Cell.hpp:108
auto & particles()
Particles.
Definition Cell.hpp:105
static Vector< T, N > broadcast(T const &s)
Create a vector that has all entries set to one value.
Definition Vector.hpp:110
#define GHOST_RDCE
reduce, the node entry gives the receiver
Definition ghosts.hpp:110
#define GHOST_BCST
broadcast, the node entry gives the sender
Definition ghosts.hpp:108
#define GHOST_PREFETCH
additional flag for prefetching
Definition ghosts.hpp:117
Properties for a ghost communication.
Definition ghosts.hpp:157
std::vector< GhostCommunication > communications
List of ghost communications.
Definition ghosts.hpp:166