OpenPFC  0.1.4
Phase Field Crystal simulation framework
Loading...
Searching...
No Matches
databuffer.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
43#pragma once
44
45#include <cstddef>
46#include <stdexcept>
47#include <vector>
48
50
51// CUDA headers (only when CUDA is enabled)
52#if defined(OpenPFC_ENABLE_CUDA)
53#include <cuda_runtime.h>
54#endif
55
56namespace pfc {
57namespace core {
58
68template <typename BackendTag, typename T> struct DataBuffer;
69
76template <typename T> struct DataBuffer<backend::CpuTag, T> {
77private:
78 std::vector<T> m_data;
79
80public:
85 explicit DataBuffer(size_t size) : m_data(size) {}
86
90 DataBuffer() = default;
91
95 DataBuffer(const DataBuffer &) = default;
96
100 DataBuffer &operator=(const DataBuffer &) = default;
101
106
111
116
121 T *data() { return m_data.data(); }
122
127 const T *data() const { return m_data.data(); }
128
133 size_t size() const { return m_data.size(); }
134
139 bool empty() const { return m_data.empty(); }
140
146 T &operator[](size_t i) { return m_data[i]; }
147
153 const T &operator[](size_t i) const { return m_data[i]; }
154
167 std::vector<T> &as_vector() { return m_data; }
168
173 const std::vector<T> &as_vector() const { return m_data; }
174
180 void copy_from_host(const std::vector<T> &src) {
181 if (src.size() != m_data.size()) {
182 throw std::runtime_error("Size mismatch in copy_from_host: expected " +
183 std::to_string(m_data.size()) + ", got " +
184 std::to_string(src.size()));
185 }
186 std::copy(src.begin(), src.end(), m_data.begin());
187 }
188
193 std::vector<T> to_host() const { return m_data; }
194
199 void resize(size_t new_size) { m_data.resize(new_size); }
200};
201
202#if defined(OpenPFC_ENABLE_CUDA)
209template <typename T> struct DataBuffer<backend::CudaTag, T> {
210private:
211 T *m_device_ptr = nullptr;
212 size_t m_size = 0;
213
214public:
220 explicit DataBuffer(size_t size) : m_size(size) {
221 if (size > 0) {
222 cudaError_t err = cudaMalloc(&m_device_ptr, size * sizeof(T));
223 if (err != cudaSuccess) {
224 throw std::runtime_error("CUDA allocation failed: " +
225 std::string(cudaGetErrorString(err)));
226 }
227 }
228 }
229
233 DataBuffer() = default;
234
238 ~DataBuffer() {
239 if (m_device_ptr != nullptr) {
240 cudaFree(m_device_ptr);
241 }
242 }
243
247 DataBuffer(const DataBuffer &) = delete;
248
252 DataBuffer &operator=(const DataBuffer &) = delete;
253
257 DataBuffer(DataBuffer &&other) noexcept
258 : m_device_ptr(other.m_device_ptr), m_size(other.m_size) {
259 other.m_device_ptr = nullptr;
260 other.m_size = 0;
261 }
262
266 DataBuffer &operator=(DataBuffer &&other) noexcept {
267 if (this != &other) {
268 if (m_device_ptr != nullptr) {
269 cudaFree(m_device_ptr);
270 }
271 m_device_ptr = other.m_device_ptr;
272 m_size = other.m_size;
273 other.m_device_ptr = nullptr;
274 other.m_size = 0;
275 }
276 return *this;
277 }
278
283 T *data() { return m_device_ptr; }
284
289 const T *data() const { return m_device_ptr; }
290
295 size_t size() const { return m_size; }
296
301 bool empty() const { return m_size == 0; }
302
303 // Note: No operator[] - can't dereference device pointer on host!
304
310 void copy_from_host(const std::vector<T> &src) {
311 if (src.size() != m_size) {
312 throw std::runtime_error("Size mismatch in copy_from_host: expected " +
313 std::to_string(m_size) + ", got " +
314 std::to_string(src.size()));
315 }
316 if (m_size > 0) {
317 cudaError_t err = cudaMemcpy(m_device_ptr, src.data(), m_size * sizeof(T),
318 cudaMemcpyHostToDevice);
319 if (err != cudaSuccess) {
320 throw std::runtime_error("CUDA copy failed: " +
321 std::string(cudaGetErrorString(err)));
322 }
323 }
324 }
325
331 std::vector<T> to_host() const {
332 std::vector<T> result(m_size);
333 if (m_size > 0) {
334 cudaError_t err = cudaMemcpy(result.data(), m_device_ptr, m_size * sizeof(T),
335 cudaMemcpyDeviceToHost);
336 if (err != cudaSuccess) {
337 throw std::runtime_error("CUDA copy failed: " +
338 std::string(cudaGetErrorString(err)));
339 }
340 }
341 return result;
342 }
343
349 void resize(size_t new_size) {
350 if (m_device_ptr != nullptr) {
351 cudaFree(m_device_ptr);
352 m_device_ptr = nullptr;
353 }
354 m_size = new_size;
355 if (new_size > 0) {
356 cudaError_t err = cudaMalloc(&m_device_ptr, new_size * sizeof(T));
357 if (err != cudaSuccess) {
358 throw std::runtime_error("CUDA allocation failed: " +
359 std::string(cudaGetErrorString(err)));
360 }
361 }
362 }
363};
364#endif // OpenPFC_ENABLE_CUDA
365
366#if defined(OpenPFC_ENABLE_HIP)
373template <typename T> struct DataBuffer<backend::HipTag, T> {
374private:
375 T *m_device_ptr = nullptr;
376 size_t m_size = 0;
377
378public:
384 explicit DataBuffer(size_t size) : m_size(size) {
385 if (size > 0) {
386 hipError_t err = hipMalloc(&m_device_ptr, size * sizeof(T));
387 if (err != hipSuccess) {
388 throw std::runtime_error("HIP allocation failed: " +
389 std::string(hipGetErrorString(err)));
390 }
391 }
392 }
393
397 DataBuffer() = default;
398
402 ~DataBuffer() {
403 if (m_device_ptr != nullptr) {
404 hipFree(m_device_ptr);
405 }
406 }
407
411 DataBuffer(const DataBuffer &) = delete;
412
416 DataBuffer &operator=(const DataBuffer &) = delete;
417
421 DataBuffer(DataBuffer &&other) noexcept
422 : m_device_ptr(other.m_device_ptr), m_size(other.m_size) {
423 other.m_device_ptr = nullptr;
424 other.m_size = 0;
425 }
426
430 DataBuffer &operator=(DataBuffer &&other) noexcept {
431 if (this != &other) {
432 if (m_device_ptr != nullptr) {
433 hipFree(m_device_ptr);
434 }
435 m_device_ptr = other.m_device_ptr;
436 m_size = other.m_size;
437 other.m_device_ptr = nullptr;
438 other.m_size = 0;
439 }
440 return *this;
441 }
442
447 T *data() { return m_device_ptr; }
448
453 const T *data() const { return m_device_ptr; }
454
459 size_t size() const { return m_size; }
460
465 bool empty() const { return m_size == 0; }
466
467 // Note: No operator[] - can't dereference device pointer on host!
468
474 void copy_from_host(const std::vector<T> &src) {
475 if (src.size() != m_size) {
476 throw std::runtime_error("Size mismatch in copy_from_host: expected " +
477 std::to_string(m_size) + ", got " +
478 std::to_string(src.size()));
479 }
480 if (m_size > 0) {
481 hipError_t err = hipMemcpy(m_device_ptr, src.data(), m_size * sizeof(T),
482 hipMemcpyHostToDevice);
483 if (err != hipSuccess) {
484 throw std::runtime_error("HIP copy failed: " +
485 std::string(hipGetErrorString(err)));
486 }
487 }
488 }
489
495 std::vector<T> to_host() const {
496 std::vector<T> result(m_size);
497 if (m_size > 0) {
498 hipError_t err = hipMemcpy(result.data(), m_device_ptr, m_size * sizeof(T),
499 hipMemcpyDeviceToHost);
500 if (err != hipSuccess) {
501 throw std::runtime_error("HIP copy failed: " +
502 std::string(hipGetErrorString(err)));
503 }
504 }
505 return result;
506 }
507
513 void resize(size_t new_size) {
514 if (m_device_ptr != nullptr) {
515 hipFree(m_device_ptr);
516 m_device_ptr = nullptr;
517 }
518 m_size = new_size;
519 if (new_size > 0) {
520 hipError_t err = hipMalloc(&m_device_ptr, new_size * sizeof(T));
521 if (err != hipSuccess) {
522 throw std::runtime_error("HIP allocation failed: " +
523 std::string(hipGetErrorString(err)));
524 }
525 }
526 }
527};
528#endif // OpenPFC_ENABLE_HIP
529
530} // namespace core
531} // namespace pfc
Backend tags for compile-time backend selection.
DataBuffer(size_t size)
Constructs a CPU buffer with the given size.
Definition databuffer.hpp:85
DataBuffer & operator=(const DataBuffer &)=default
Copy assignment.
DataBuffer(const DataBuffer &)=default
Copy constructor.
void resize(size_t new_size)
Resize the buffer.
Definition databuffer.hpp:199
DataBuffer(DataBuffer &&) noexcept=default
Move constructor.
DataBuffer()=default
Default constructor (empty buffer)
std::vector< T > to_host() const
Copy data to host vector.
Definition databuffer.hpp:193
bool empty() const
Returns true if buffer is empty.
Definition databuffer.hpp:139
void copy_from_host(const std::vector< T > &src)
Copy data from host vector.
Definition databuffer.hpp:180
const T & operator[](size_t i) const
Const element access operator (CPU only)
Definition databuffer.hpp:153
size_t size() const
Returns the number of elements.
Definition databuffer.hpp:133
const std::vector< T > & as_vector() const
Get underlying std::vector const reference (for Model compatibility)
Definition databuffer.hpp:173
T & operator[](size_t i)
Element access operator (CPU only)
Definition databuffer.hpp:146
std::vector< T > & as_vector()
Get underlying std::vector reference (for Model compatibility)
Definition databuffer.hpp:167
const T * data() const
Returns const pointer to underlying data.
Definition databuffer.hpp:127
Backend-agnostic memory buffer.
Definition databuffer.hpp:68
Represents the global simulation domain (the "world").
Definition world.hpp:91
const Int3 m_size
Grid dimensions: {nx, ny, nz}.
Definition world.hpp:94