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
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.