ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
GpuParticleData.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#ifdef CUDA
23
24#include "GpuParticleData.hpp"
25
27#include "communication.hpp"
29#include "system/System.hpp"
30
31#include <utils/Span.hpp>
32#include <utils/Vector.hpp>
35
36#include <boost/serialization/array.hpp>
37#include <boost/serialization/is_bitwise_serializable.hpp>
38#include <boost/serialization/split_free.hpp>
39
40#include <vector>
41
42void GpuParticleData::enable_particle_transfer() {
43 if (m_need_particles_update and not m_communication_enabled) {
44 if (::this_node == 0) {
45 gpu_init_particle_comm();
46 }
47 m_communication_enabled = true;
48 }
49}
50
51void GpuParticleData::copy_particles_to_device() {
52 auto const &cell_structure = *System::get_system().cell_structure;
53 copy_particles_to_device(cell_structure.local_particles(), ::this_node);
54}
55
57 auto result = false;
58 if (::this_node == 0) {
59 result = has_compatible_device_impl();
60 }
61 boost::mpi::broadcast(::comm_cart, result, 0);
62 return result;
63}
64
65BOOST_IS_BITWISE_SERIALIZABLE(GpuParticleData::GpuParticle)
66
67namespace boost {
68namespace serialization {
69template <typename Archive>
70void load(Archive &ar, GpuParticleData::GpuParticle &p, unsigned const) {
71 ar >> make_array(reinterpret_cast<char *>(&p),
73}
74template <typename Archive>
75void save(Archive &ar, GpuParticleData::GpuParticle const &p, unsigned const) {
76 ar << make_array(reinterpret_cast<char const *>(&p),
78}
79} // namespace serialization
80} // namespace boost
81
82BOOST_SERIALIZATION_SPLIT_FREE(GpuParticleData::GpuParticle)
83
84static void pack_particles(ParticleRange const &particles,
85 GpuParticleData::GpuParticle *buffer) {
86 auto const &box = *System::get_system().box_geo;
87 unsigned long int i = 0u;
88 for (auto const &p : particles) {
89 buffer[i].p = static_cast<Utils::Vector3f>(box.folded_position(p.pos()));
90#ifdef DIPOLES
91 buffer[i].dip = static_cast<Utils::Vector3f>(p.calc_dip());
92#endif
93#ifdef ELECTROSTATICS
94 buffer[i].q = static_cast<float>(p.q());
95#endif
96 buffer[i].identity = p.id();
97 i++;
98 }
99}
100
101void GpuParticleData::gather_particle_data(
102 ParticleRange const &particles,
103 pinned_vector<GpuParticle> &particle_data_host, int this_node) {
104 auto const n_part = particles.size();
105
106 if (this_node > 0) {
107 static std::vector<GpuParticle> buffer;
108 buffer.resize(n_part);
109 /* pack local parts into buffer */
110 pack_particles(particles, buffer.data());
111
113 } else {
114 particle_data_host.resize(n_part);
115
116 /* Pack own particles */
117 pack_particles(particles, particle_data_host.data());
118
119 Utils::Mpi::gather_buffer(particle_data_host, comm_cart);
120 }
121}
122
123/**
124 * @brief Add a flat force (and torque) array to a range of particles.
125 *
126 * @param particles The particles the forces (and torques) should be added to
127 * @param forces The forces as flat array of size 3 * particles.size()
128 * @param torques The torques as flat array of size 3 * particles.size(),
129 * this is only touched if ROTATION is active.
130 */
131static void add_forces_and_torques(ParticleRange const &particles,
133 Utils::Span<const float> torques) {
134 unsigned long int i = 0u;
135 for (auto &p : particles) {
136 for (unsigned long int j = 0u; j < 3u; j++) {
137 p.force()[j] += static_cast<double>(forces[3ul * i + j]);
138#ifdef ROTATION
139 p.torque()[j] += static_cast<double>(torques[3ul * i + j]);
140#endif
141 }
142 i++;
143 }
144}
145
146/**
147 * @brief Distribute forces to the worker nodes, and add them to the particles.
148 *
149 * @param particles The particles for which the forces (and torques) should
150 * be added to.
151 * @param host_forces The forces as flat array of size 3 * particles.size(),
152 * only relevant on the head node.
153 * @param host_torques The torques as flat array of size 3 * particles.size(),
154 * this is only touched if ROTATION is active. Only
155 * relevant on the head node.
156 */
157void GpuParticleData::particles_scatter_forces(
158 ParticleRange const &particles, Utils::Span<float> host_forces,
159 Utils::Span<float> host_torques) const {
160
161 auto const size = 3ul * particles.size();
162 auto const n_elements = static_cast<int>(size);
163
164 if (::this_node > 0) {
165 static std::vector<float> buffer_forces;
166 static std::vector<float> buffer_torques;
167
168 buffer_forces.resize(size);
169 Utils::Mpi::scatter_buffer(buffer_forces.data(), n_elements, ::comm_cart);
170#ifdef ROTATION
171 buffer_torques.resize(size);
172 Utils::Mpi::scatter_buffer(buffer_torques.data(), n_elements, ::comm_cart);
173#endif
174 add_forces_and_torques(particles, buffer_forces, buffer_torques);
175 } else {
176 Utils::Mpi::scatter_buffer(host_forces.data(), n_elements, ::comm_cart);
177#ifdef ROTATION
178 Utils::Mpi::scatter_buffer(host_torques.data(), n_elements, ::comm_cart);
179#endif
180 add_forces_and_torques(particles, host_forces, host_torques);
181 }
182}
183
184#endif
std::vector< T, CudaHostAllocator< T > > pinned_vector
static void add_forces_and_torques(ParticleRange const &particles, Utils::Span< const float > forces, Utils::Span< const float > torques)
Add a flat force (and torque) array to a range of particles.
static void pack_particles(ParticleRange const &particles, GpuParticleData::GpuParticle *buffer)
Vector implementation and trait types for boost qvm interoperability.
float u[3]
Particle data communication manager for the GPU.
bool has_compatible_device() const
A range of particles.
base_type::size_type size() const
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
A stripped-down version of std::span from C++17.
Definition Span.hpp:38
DEVICE_QUALIFIER constexpr pointer data() const
Definition Span.hpp:108
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
This file contains the defaults for ESPResSo.
ParticleRange particles(Utils::Span< Cell *const > cells)
System & get_system()
void gather_buffer(std::vector< T, Allocator > &buffer, boost::mpi::communicator const &comm, int root=0)
Gather buffer with different size on each node.
void scatter_buffer(T *buffer, int n_elem, boost::mpi::communicator comm, int root=0)
Scatter buffer with different size on each node.
void load(Archive &ar, GpuParticleData::GpuParticle &p, unsigned const)
void save(Archive &ar, GpuParticleData::GpuParticle const &p, unsigned const)
Subset of Particle which is copied to the GPU.