NeoFOAM
WIP Prototype of a modern OpenFOAM core
Loading...
Searching...
No Matches
field.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2023 NeoFOAM authors
3#pragma once
4
5#include <Kokkos_Core.hpp>
6
7#include <iostream>
8#include <span>
9
15
16namespace NeoFOAM
17{
18
19namespace detail
20{
29template<typename ValueType>
30auto deepCopyVisitor(size_t size, const ValueType* srcPtr, ValueType* dstPtr)
31{
32 return [size, srcPtr, dstPtr](const auto& srcExec, const auto& dstExec)
33 {
34 Kokkos::deep_copy(
35 dstExec.createKokkosView(dstPtr, size), srcExec.createKokkosView(srcPtr, size)
36 );
37 };
38}
39}
40
47template<typename ValueType>
48class Field
49{
50
51public:
52
58 Field(const Executor& exec, size_t size) : size_(size), data_(nullptr), exec_(exec)
59 {
60 void* ptr = nullptr;
61 std::visit(
62 [&ptr, size](const auto& concreteExec)
63 { ptr = concreteExec.alloc(size * sizeof(ValueType)); },
64 exec_
65 );
66 data_ = static_cast<ValueType*>(ptr);
67 }
68
77 const Executor& exec, const ValueType* in, size_t size, Executor hostExec = SerialExecutor()
78 )
79 : size_(size), data_(nullptr), exec_(exec)
80 {
81 void* ptr = nullptr;
82 std::visit(
83 [&ptr, size](const auto& concreteExec)
84 { ptr = concreteExec.alloc(size * sizeof(ValueType)); },
85 exec_
86 );
87 data_ = static_cast<ValueType*>(ptr);
88 std::visit(detail::deepCopyVisitor<ValueType>(size_, in, data_), hostExec, exec_);
89 }
90
97 Field(const Executor& exec, size_t size, ValueType value)
98 : size_(size), data_(nullptr), exec_(exec)
99 {
100 void* ptr = nullptr;
101 std::visit(
102 [&ptr, size](const auto& execu) { ptr = execu.alloc(size * sizeof(ValueType)); }, exec_
103 );
104 data_ = static_cast<ValueType*>(ptr);
105 NeoFOAM::fill(*this, value);
106 }
107
113 Field(const Executor& exec, std::vector<ValueType> in) : Field(exec, in.data(), in.size()) {}
114
121 : Field(exec, in.data(), in.size(), in.exec())
122 {}
123
128 Field(const Field<ValueType>& rhs) : data_(nullptr), exec_(rhs.exec_)
129 {
130 resize(rhs.size_);
131 setField(*this, rhs.span());
132 }
133
138 Field(Field<ValueType>&& rhs) noexcept : size_(rhs.size_), data_(rhs.data_), exec_(rhs.exec_)
139 {
140 rhs.data_ = nullptr;
141 rhs.size_ = 0;
142 }
143
148 {
149 std::visit([this](const auto& exec) { exec.free(data_); }, exec_);
150 data_ = nullptr;
151 }
152
158 template<typename func>
159 void apply(func f)
160 {
161 map(*this, f);
162 }
163
169 [[nodiscard]] Field<ValueType> copyToExecutor(Executor dstExec) const
170 {
171 if (dstExec == exec_) return *this;
172
173 Field<ValueType> result(dstExec, size_);
174 std::visit(detail::deepCopyVisitor(size_, data_, result.data()), exec_, dstExec);
175
176 return result;
177 }
178
183 [[nodiscard]] Field<ValueType> copyToHost() const { return copyToExecutor(SerialExecutor()); }
184
194 {
196 result.size() == size_, "Parsed Field size not the same as current field size"
197 );
198 result = copyToExecutor(SerialExecutor());
199 }
200
206 KOKKOS_INLINE_FUNCTION
207 ValueType& operator[](const size_t i) { return data_[i]; }
208
214 KOKKOS_INLINE_FUNCTION
215 const ValueType& operator[](const size_t i) const { return data_[i]; }
216
222 KOKKOS_INLINE_FUNCTION
223 ValueType& operator()(const size_t i) { return data_[i]; }
224
230 KOKKOS_INLINE_FUNCTION
231 const ValueType& operator()(const size_t i) const { return data_[i]; }
232
237 void operator=(const ValueType& rhs) { fill(*this, rhs); }
238
246 {
247 NF_ASSERT(exec_ == rhs.exec_, "Executors are not the same");
248 if (this->size() != rhs.size())
249 {
250 this->resize(rhs.size());
251 }
252 setField(*this, rhs.span());
253 }
254
261 {
262 validateOtherField(rhs);
263 add(*this, rhs);
264 return *this;
265 }
266
273 {
274 validateOtherField(rhs);
275 sub(*this, rhs);
276 return *this;
277 }
278
284 [[nodiscard]] Field<ValueType> operator*(const Field<scalar>& rhs)
285 {
286 validateOtherField(rhs);
287 Field<ValueType> result(exec_, size_);
288 result = *this;
289 mul(result, rhs);
290 return result;
291 }
292
299 [[nodiscard]] Field<ValueType> operator*(const scalar rhs)
300 {
301 Field<ValueType> result(exec_, size_);
302 result = *this;
303 scalarMul(result, rhs);
304 return result;
305 }
306
311 void resize(const size_t size)
312 {
313 void* ptr = nullptr;
314 if (!empty())
315 {
316 std::visit(
317 [this, &ptr, size](const auto& exec)
318 { ptr = exec.realloc(this->data_, size * sizeof(ValueType)); },
319 exec_
320 );
321 }
322 else
323 {
324 std::visit(
325 [&ptr, size](const auto& exec) { ptr = exec.alloc(size * sizeof(ValueType)); },
326 exec_
327 );
328 }
329 data_ = static_cast<ValueType*>(ptr);
330 size_ = size;
331 }
332
337 [[nodiscard]] ValueType* data() { return data_; }
338
343 [[nodiscard]] const ValueType* data() const { return data_; }
344
349 [[nodiscard]] const Executor& exec() const { return exec_; }
350
355 [[nodiscard]] size_t size() const { return size_; }
356
361 [[nodiscard]] bool empty() const { return size() == 0; }
362
363 // ensures no return a span of a temporary object --> invalid memory access
364 std::span<ValueType> span() && = delete;
365
366 // ensures no return a span of a temporary object --> invalid memory access
367 std::span<const ValueType> span() const&& = delete;
368
373 [[nodiscard]] std::span<ValueType> span() & { return std::span<ValueType>(data_, size_); }
374
379 [[nodiscard]] std::span<const ValueType> span() const&
380 {
381 return std::span<const ValueType>(data_, size_);
382 }
383
384 // ensures no return a span of a temporary object --> invalid memory access
385 [[nodiscard]] std::span<ValueType> span(std::pair<size_t, size_t> range) && = delete;
386
387 // ensures no return a span of a temporary object --> invalid memory access
388 [[nodiscard]] std::span<const ValueType> span(std::pair<size_t, size_t> range) const&& = delete;
389
394 [[nodiscard]] std::span<ValueType> span(std::pair<size_t, size_t> range) &
395 {
396 return std::span<ValueType>(data_ + range.first, range.second - range.first);
397 }
398
403 [[nodiscard]] std::span<const ValueType> span(std::pair<size_t, size_t> range) const&
404 {
405 return std::span<const ValueType>(data_ + range.first, range.second - range.first);
406 }
407
412 [[nodiscard]] std::pair<size_t, size_t> range() const { return {0, size()}; }
413
414private:
415
416 size_t size_ {0};
417 ValueType* data_ {nullptr};
418 const Executor exec_;
419
424 void validateOtherField(const Field<ValueType>& rhs) const
425 {
426 NF_DEBUG_ASSERT(size() == rhs.size(), "Fields are not the same size.");
427 NF_DEBUG_ASSERT(exec() == rhs.exec(), "Executors are not the same.");
428 }
429};
430
437template<typename T>
438[[nodiscard]] Field<T> operator+(Field<T> lhs, const Field<T>& rhs)
439{
440 lhs += rhs;
441 return lhs;
442}
443
450template<typename T>
451[[nodiscard]] Field<T> operator-(Field<T> lhs, const Field<T>& rhs)
452{
453 lhs -= rhs;
454 return lhs;
455}
456
457} // namespace NeoFOAM
A class to contain the data and executors for a field and define some basic operations.
Definition field.hpp:49
Field< ValueType > & operator-=(const Field< ValueType > &rhs)
Arithmetic subtraction operator, subtraction by a second field.
Definition field.hpp:272
bool empty() const
Checks if the field is empty.
Definition field.hpp:361
Field< ValueType > operator*(const scalar rhs)
Arithmetic multiply operator, multiplies every cell in the field by a scalar.
Definition field.hpp:299
void resize(const size_t size)
Resizes the field to a new size.
Definition field.hpp:311
std::pair< size_t, size_t > range() const
Gets the range of the field.
Definition field.hpp:412
void operator=(const ValueType &rhs)
Assignment operator, Sets the field values to that of the passed value.
Definition field.hpp:237
size_t size() const
Gets the size of the field.
Definition field.hpp:355
const Executor & exec() const
Gets the executor associated with the field.
Definition field.hpp:349
KOKKOS_INLINE_FUNCTION ValueType & operator()(const size_t i)
Function call operator.
Definition field.hpp:223
Field< ValueType > copyToHost() const
Returns a copy of the field back to the host.
Definition field.hpp:183
Field(const Executor &exec, const ValueType *in, size_t size, Executor hostExec=SerialExecutor())
Create a Field with a given size from existing memory on an executor.
Definition field.hpp:76
KOKKOS_INLINE_FUNCTION ValueType & operator[](const size_t i)
Subscript operator.
Definition field.hpp:207
void copyToHost(Field< ValueType > &result)
Copies the data (from anywhere) to a parsed host field.
Definition field.hpp:193
std::span< ValueType > span(std::pair< size_t, size_t > range) &
Gets a sub view of the field as a span.
Definition field.hpp:394
Field(const Executor &exec, size_t size)
Create an uninitialized Field with a given size on an executor.
Definition field.hpp:58
ValueType * data()
Direct access to the underlying field data.
Definition field.hpp:337
const ValueType * data() const
Direct access to the underlying field data.
Definition field.hpp:343
KOKKOS_INLINE_FUNCTION const ValueType & operator[](const size_t i) const
Subscript operator.
Definition field.hpp:215
~Field()
Destroy the Field object.
Definition field.hpp:147
void operator=(const Field< ValueType > &rhs)
Assignment operator, Sets the field values to that of the parsed field.
Definition field.hpp:245
std::span< const ValueType > span(std::pair< size_t, size_t > range) const &
Gets a sub view of the field as a span.
Definition field.hpp:403
std::span< ValueType > span() &&=delete
std::span< const ValueType > span() const &&=delete
Field(const Field< ValueType > &rhs)
Copy constructor, creates a new field with the same size and data as the parsed field.
Definition field.hpp:128
void apply(func f)
applies a functor, transformation, to the field
Definition field.hpp:159
std::span< const ValueType > span(std::pair< size_t, size_t > range) const &&=delete
Field< ValueType > operator*(const Field< scalar > &rhs)
Arithmetic multiply operator, multiply by a second field.
Definition field.hpp:284
Field(const Executor &exec, const Field< ValueType > &in)
Create a Field as a copy of a Field on a specified executor.
Definition field.hpp:120
Field< ValueType > & operator+=(const Field< ValueType > &rhs)
Arithmetic add operator, addition of a second field.
Definition field.hpp:260
std::span< const ValueType > span() const &
Gets the field as a span.
Definition field.hpp:379
Field(const Executor &exec, size_t size, ValueType value)
Create a Field with a given size on an executor and uniform value.
Definition field.hpp:97
Field(const Executor &exec, std::vector< ValueType > in)
Create a Field from a given vector of values on an executor.
Definition field.hpp:113
std::span< ValueType > span(std::pair< size_t, size_t > range) &&=delete
KOKKOS_INLINE_FUNCTION const ValueType & operator()(const size_t i) const
Function call operator.
Definition field.hpp:231
Field(Field< ValueType > &&rhs) noexcept
Move constructor, moves the data from the parsed field to the new field.
Definition field.hpp:138
Field< ValueType > copyToExecutor(Executor dstExec) const
Copies the data to a new field on a specific executor.
Definition field.hpp:169
Reference executor for serial CPU execution.
#define NF_ASSERT(condition, message)
Macro for asserting a condition and printing an error message if the condition is false.
Definition error.hpp:142
#define NF_DEBUG_ASSERT(condition, message)
Macro for asserting a condition and printing an error message if the condition is false (only in debu...
Definition error.hpp:211
auto deepCopyVisitor(size_t size, const ValueType *srcPtr, ValueType *dstPtr)
A helper function to simplify the common pattern of copying between and to executor.
Definition field.hpp:30
float scalar
Definition scalar.hpp:11
void mul(Field< ValueType > &a, const Field< std::type_identity_t< ValueType > > &b)
void setField(Field< ValueType > &a, const std::span< const std::type_identity_t< ValueType > > b, std::pair< size_t, size_t > range={0, 0})
Set the field with a span of values using a specific executor.
void add(Field< ValueType > &a, const Field< std::type_identity_t< ValueType > > &b)
void map(Field< T > &a, const Inner inner, std::pair< size_t, size_t > range={0, 0})
Map a field using a specific executor.
Field< T > operator+(Field< T > lhs, const Field< T > &rhs)
Arithmetic add operator, addition of two fields.
Definition field.hpp:438
Field< T > operator-(Field< T > lhs, const Field< T > &rhs)
Arithmetic subtraction operator, subtraction one field from another.
Definition field.hpp:451
void sub(Field< ValueType > &a, const Field< std::type_identity_t< ValueType > > &b)
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:16
void scalarMul(Field< ValueType > &a, const std::type_identity_t< ValueType > value)
void fill(Field< ValueType > &a, const std::type_identity_t< ValueType > value, std::pair< size_t, size_t > range={0, 0})
Fill the field with a scalar value using a specific executor.