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