Documentation 6b54b78464
Loading...
Searching...
No Matches
CSysVector.hpp
Go to the documentation of this file.
1/*!
2 * \file CSysVector.hpp
3 * \brief Declararion and inlines of the vector class used in the
4 * solution of large, distributed, sparse linear systems.
5 * \author P. Gomes, F. Palacios, J. Hicken, T. Economon
6 * \version 8.5.0 "Harrier"
7 *
8 * SU2 Project Website: https://su2code.github.io
9 *
10 * The SU2 Project is maintained by the SU2 Foundation
11 * (http://su2foundation.org)
12 *
13 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
14 *
15 * SU2 is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * SU2 is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
27 */
28
29#pragma once
30
31#include <memory>
32#include <vector>
33
34#include "../code_config.hpp"
35#include "../parallelization/mpi_structure.hpp"
36#include "../parallelization/omp_structure.hpp"
37#include "../parallelization/vectorization.hpp"
39#include "../../include/CConfig.hpp"
40
41#ifdef __CUDACC__
42#include "GPUComms.cuh"
43#endif
44
45template <class ScalarType>
46class CSysVector;
47
48/*!
49 * \brief True for the plain floating-point scalar types the GPU vector kernels
50 * (CSysVectorGPU.cu) are instantiated for, in builds where those kernels
51 * exist at all. AD active types are never dispatched to the device: the
52 * tape/expression machinery those types pull in is not compatible with
53 * nvcc's device-code compilation, and device-resident autodiff is not
54 * supported by this GPU path.
55 * \note In an AD build this is false even for su2mixedfloat, because the .cu
56 * translation units are not linked into the AD libraries (see
57 * SU2_ENABLE_CUDA_KERNELS in code_config.hpp).
58 */
59#ifdef SU2_ENABLE_CUDA_KERNELS
60template <class ScalarType>
61inline constexpr bool su2_gpu_capable_v = std::is_floating_point_v<ScalarType>;
62#else
63template <class ScalarType>
64inline constexpr bool su2_gpu_capable_v = false;
65#endif
66
67/*!
68 * \brief OpenMP worksharing construct used in CSysVector for loops.
69 * \note The loop will only run in parallel if methods are called from a
70 * parallel region (if not the results will still be correct).
71 * Static schedule to reduce overhead, chunk size determined at initialization.
72 * "nowait" clause is safe when calling CSysVector methods after each other
73 * as the loop size is the same. Methods of other classes that operate on a
74 * CSysVector and do not have the same work scheduling must use a
75 * SU2_OMP_BARRIER before using the vector.
76 */
77#ifdef HAVE_OMP
78#ifdef HAVE_OMP_SIMD
79#define CSYSVEC_PARFOR SU2_OMP_FOR_(simd schedule(static, omp_chunk_size) SU2_NOWAIT)
80#else
81#define CSYSVEC_PARFOR SU2_OMP_FOR_(schedule(static, omp_chunk_size) SU2_NOWAIT)
82#endif
83#define END_CSYSVEC_PARFOR END_SU2_OMP_FOR
84#else
85#define CSYSVEC_PARFOR SU2_OMP_SIMD
86#define END_CSYSVEC_PARFOR
87#endif
88
89/*!
90 * \brief Brackets device work so that it is issued by a single thread with the whole team
91 * synchronized before and after.
92 * \note The GPU is one shared resource and the device path does not use OpenMP worksharing.
93 * Issuing from one thread keeps kernel launches ordered on the default stream and, above
94 * all, stops part of a team from entering a worksharing construct that the rest skipped.
95 * Correctness relies on all threads reaching the same vector operations in the same order,
96 * which is the assumption the "nowait" clause on CSYSVEC_PARFOR already makes. These
97 * regions must not be nested; they are used by the operations of this class and by the
98 * matrix-vector product and preconditioner wrappers, and by nothing above those.
99 */
100#define SU2_DEVICE_REGION(...) SU2_OMP_SAFE_GLOBAL_ACCESS(__VA_ARGS__)
101#define BEGIN_SU2_DEVICE_REGION BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS
102#define END_SU2_DEVICE_REGION END_SU2_OMP_SAFE_GLOBAL_ACCESS
103
104namespace VecExpr {
105
107
108/*!
109 * \brief Whether vector expressions are currently evaluated on the device.
110 * \note Defined in CSysVectorGPU.cu. This is a plain global, not per thread: every thread
111 * of a team has to agree on it or they would split over the worksharing constructs below.
112 * It is switched by CSysSolve at the same boundary that uploads and downloads the vectors
113 * (HandleTemporariesIn/Out), and nowhere else, so it does not change while a solve runs.
114 */
115#ifdef SU2_ENABLE_CUDA_KERNELS
117void SetUseDeviceExpressions(bool use);
118#else
119inline bool UseDeviceExpressions() { return false; }
120inline void SetUseDeviceExpressions(bool) {}
121#endif
122
123/*!
124 * \brief How a CSysVector is captured inside an expression: a bare pointer to whichever
125 * storage the expression is going to be evaluated from.
126 * \note Capturing by value (rather than a reference to the vector) is what makes an
127 * arbitrary expression tree trivially copyable, and therefore passable by value to the
128 * assignment kernel. The choice of storage is fixed when the expression is built, which is
129 * sound because there is no fallback: while UseDeviceExpressions() holds, every expression
130 * is evaluated by a kernel.
131 */
132template <class Scalar>
133class CVectorView : public CVecExpr<CVectorView<Scalar>, Scalar> {
134 private:
135 const Scalar* data = nullptr;
136
137 public:
138 static constexpr bool StoreAsRef = false;
139
140 CVectorView(const CSysVector<Scalar>& vector);
141
142 SU2_CUDA_HOST_DEVICE FORCEINLINE const Scalar& operator[](size_t i) const { return data[i]; }
143};
144
145template <class Scalar>
149
150template <class Scalar>
154
155template <DeviceAssignOp Op, class Scalar, class T>
156void AssignDeviceExpression(Scalar* data, unsigned long size, const CVecExpr<T, Scalar>& expr);
157
158#ifdef __CUDACC__
159template <DeviceAssignOp Op, class Scalar, class T>
160__global__ void DeviceAssignKernel(Scalar* data, unsigned long size, T expr) {
161 const unsigned long i = static_cast<unsigned long>(blockIdx.x) * blockDim.x + threadIdx.x;
162 if (i >= size) return;
163
164 if constexpr (Op == DeviceAssignOp::Assign) {
165 data[i] = expr[i];
166 } else if constexpr (Op == DeviceAssignOp::Add) {
167 data[i] += expr[i];
168 } else if constexpr (Op == DeviceAssignOp::Subtract) {
169 data[i] -= expr[i];
170 } else if constexpr (Op == DeviceAssignOp::Multiply) {
171 data[i] *= expr[i];
172 } else {
173 data[i] /= expr[i];
174 }
175}
176
177template <DeviceAssignOp Op, class Scalar, class T>
178inline void AssignDeviceExpression(Scalar* data, unsigned long size, const CVecExpr<T, Scalar>& expr) {
179 if (size == 0) return;
180 constexpr unsigned block_size = 256;
181 const auto grid_size = static_cast<unsigned>((size + block_size - 1) / block_size);
182 DeviceAssignKernel<Op><<<grid_size, block_size>>>(data, size, expr.derived());
183 gpuErrChk(cudaPeekAtLastError());
184}
185#endif
186
187} // namespace VecExpr
188
189/*!
190 * \class CSysVector
191 * \ingroup SpLinSys
192 * \brief Class for holding and manipulating vectors needed by linear solvers.
193 */
194template <class ScalarType>
195class CSysVector : public VecExpr::CVecExpr<CSysVector<ScalarType>, ScalarType> {
196 private:
197 enum { OMP_MAX_SIZE = 4096 }; /*!< \brief Maximum chunk size used in parallel for loops. */
198
199 /// NOTE: Update swap() if you add member variables.
200 unsigned long omp_chunk_size = OMP_MAX_SIZE; /*!< \brief Static chunk size used in loops. */
201 ScalarType* vec_val = nullptr; /*!< \brief Storage, 64 byte aligned (do not use normal new/delete). */
202 unsigned long nElm = 0; /*!< \brief Total number of elements (or number elements on this processor). */
203 unsigned long nElmDomain = 0; /*!< \brief Total number of elements without Ghost cells. */
204 unsigned long nVar = 1; /*!< \brief Number of elements in a block. */
205
206 ScalarType* d_vec_val = nullptr; /*!< \brief Device Pointer to store the vector values on the GPU. */
207
208#ifdef HAVE_OMP
209 mutable std::unique_ptr<ScalarType[]>
210 dot_scratch; /*!< \brief Stores partial sums for ordered reduction over OMP threads. */
211#else
212 mutable std::array<ScalarType, 1> dot_scratch;
213#endif
214
215 /*!
216 * \brief Generic initialization from a scalar or array.
217 * \note If val==nullptr vec_val is not initialized, only allocated.
218 * \param[in] numBlk - Number of blocks locally.
219 * \param[in] numBlkDomain - Number of blocks locally (without ghost cells).
220 * \param[in] numVar - Number of variables in each block.
221 * \param[in] val - Default value for elements.
222 * \param[in] valIsArray - If true val is treated as array.
223 * \param[in] errorIfParallel - Throw error if within parallel region (all ctors except the default one do this).
224 */
225 void Initialize(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, const ScalarType* val,
226 bool valIsArray, bool errorIfParallel = true);
227
228 /*!
229 * \brief Helper to unpack (transpose) a SIMD input block.
230 */
231 template <size_t N, size_t nVar, class VecTypeSIMD, class F>
232 FORCEINLINE static void UnpackBlock(const VecTypeSIMD& in, simd::Array<F, N> mask, ScalarType out[][nVar]) {
233 static_assert(VecTypeSIMD::StaticSize, "This method requires static size vectors.");
234 for (size_t i = 0; i < nVar; ++i) {
236 for (size_t k = 0; k < N; ++k) out[k][i] = mask[k] * in[i][k];
237 }
238 }
239
240 /*!
241 * \brief Evaluates an expression into the device storage of this vector.
242 * \note The kernel has to be instantiated for the expression type in CSysVectorGPU.cu,
243 * a shape that is not in that list is an undefined symbol at link time.
244 */
245 template <VecExpr::DeviceAssignOp Op, class T>
246 CSysVector& AssignDevice(const VecExpr::CVecExpr<T, ScalarType>& expr) {
247#ifdef SU2_ENABLE_CUDA_KERNELS
248 if constexpr (su2_gpu_capable_v<ScalarType>) {
250 VecExpr::store_t<const T> stored_expr(expr.derived());
251 VecExpr::AssignDeviceExpression<Op>(d_vec_val, nElm, stored_expr);
252 }
254 }
255#endif
256 return *this;
257 }
258
259 template <VecExpr::DeviceAssignOp Op>
260 CSysVector& AssignDevice(ScalarType val) {
261#ifdef SU2_ENABLE_CUDA_KERNELS
262 if constexpr (su2_gpu_capable_v<ScalarType>) {
264 VecExpr::AssignDeviceExpression<Op>(d_vec_val, nElm, VecExpr::Bcast<ScalarType>(val));
266 }
267#endif
268 return *this;
269 }
270
271 /*!
272 * \brief GPU helper for `dot`.
273 */
274 ScalarType dotGPU(const CSysVector& other) const;
275
276 /*!
277 * \brief GPU helper for multiDot.
278 */
279 static su2matrix<ScalarType> multiDotGPU(const std::vector<CSysVector<ScalarType>>& V, size_t i0, size_t n,
280 const std::vector<CSysVector<ScalarType>>& W, size_t m);
281
282 public:
283 static constexpr bool StoreAsRef = true; /*! \brief Required by CVecExpr. */
284
285 /*!
286 * \brief Default constructor of the class.
287 */
288 CSysVector() = default;
289
290 /*!
291 * \brief Destructor
292 */
293 ~CSysVector();
294
295 /*!
296 * \brief Construct from size and value.
297 * \param[in] size - Number of elements locally.
298 * \param[in] val - Default value for elements.
299 */
300 explicit CSysVector(unsigned long size, ScalarType val = 0.0) { Initialize(size, size, 1, &val, false); }
301
302 /*!
303 * \brief Construct from size and value (block version).
304 * \param[in] numBlk - Number of blocks locally.
305 * \param[in] numBlkDomain - Number of blocks locally (without ghost cells).
306 * \param[in] numVar - Number of variables in each block.
307 * \param[in] val - Default value for elements.
308 */
309 CSysVector(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, ScalarType val = 0.0) {
310 Initialize(numBlk, numBlkDomain, numVar, &val, false);
311 }
312
313 /*!
314 * \brief Construct from array.
315 * \param[in] size - Number of elements locally.
316 * \param[in] u_array - Vector stored as array being copied.
317 */
318 CSysVector(unsigned long size, const ScalarType* u_array) { Initialize(size, size, 1, u_array, true); }
319
320 /*!
321 * \brief Constructor from array (block version).
322 * \param[in] numBlk - number of blocks locally
323 * \param[in] numBlkDomain - number of blocks locally (without g cells)
324 * \param[in] numVar - number of variables in each block
325 * \param[in] u_array - vector stored as array being copied
326 */
327 CSysVector(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, const ScalarType* u_array) {
328 Initialize(numBlk, numBlkDomain, numVar, u_array, true);
329 }
330
331 /*!
332 * \brief Copy constructor of the class.
333 * \note Not defined for expressions because we do not know their sizes.
334 * \param[in] u - Vector being copied.
335 */
336 CSysVector(const CSysVector& u) { Initialize(u.GetNBlk(), u.GetNBlkDomain(), u.nVar, u.vec_val, true); }
337
338 /*!
339 * \brief Swap contents with another vector.
340 */
341 void swap(CSysVector& other) {
342 std::swap(omp_chunk_size, other.omp_chunk_size);
343 std::swap(vec_val, other.vec_val);
344 std::swap(d_vec_val, other.d_vec_val);
345 std::swap(nElm, other.nElm);
346 std::swap(nElmDomain, other.nElmDomain);
347 std::swap(nVar, other.nVar);
348 std::swap(dot_scratch, other.dot_scratch);
349 }
350
351 /*!
352 * \brief Initialize the class with a scalar.
353 * \param[in] numBlk - number of blocks locally
354 * \param[in] numBlkDomain - number of blocks locally (without g cells)
355 * \param[in] numVar - number of variables in each block
356 * \param[in] val - default value for elements
357 */
358 void Initialize(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, ScalarType val = 0.0) {
359 Initialize(numBlk, numBlkDomain, numVar, &val, false, false);
360 }
361
362 /*!
363 * \brief Initialize the class with an array.
364 * \note If ptr==nullptr no copy occurs.
365 * \param[in] numBlk - number of blocks locally
366 * \param[in] numBlkDomain - number of blocks locally (without g cells)
367 * \param[in] numVar - number of variables in each block
368 * \param[in] ptr - pointer to data with which to initialize the vector
369 */
370 void Initialize(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, const ScalarType* ptr) {
371 Initialize(numBlk, numBlkDomain, numVar, ptr, true, false);
372 }
373
374 /*!
375 * \brief Set our values (resizing if required) by copying from other, the derivative information is lost.
376 * \param[in] other - source CSysVector
377 */
378 template <class T>
379 void PassiveCopy(const CSysVector<T>& other) {
380 /*--- This is a method and not the overload of an operator to make sure who
381 * calls it knows the consequence to the derivative information (lost) ---*/
382
383 /*--- check if self-assignment, otherwise perform deep copy ---*/
384 if ((const void*)this == (const void*)&other) return;
385
387 Initialize(other.GetNBlk(), other.GetNBlkDomain(), other.GetNVar(), nullptr, true, false);)
388
390 for (auto i = 0ul; i < nElm; i++) vec_val[i] = SU2_TYPE::GetValue(other[i]);
392 }
393
394 /*!
395 * \brief Performs the memory copy from host to device.
396 * \param[in] trigger - boolean value that decides whether to conduct the transfer or not. True by default.
397 */
398 void HtDTransfer(bool trigger = true) const;
399
400 /*!
401 * \brief Performs the memory copy from device to host.
402 * \param[in] trigger - boolean value that decides whether to conduct the transfer or not. True by default.
403 */
404 void DtHTransfer(bool trigger = true) const;
405
406 /*!
407 * \brief return device pointer that points to the CSysVector values in GPU memory
408 */
409 inline ScalarType* GetDevicePointer() const { return d_vec_val; }
410
411 /*!
412 * \brief return host pointer that points to the CSysVector values, counterpart of
413 * GetDevicePointer
414 */
415 inline const ScalarType* GetHostPointer() const { return vec_val; }
416
417 /*!
418 * \brief return the number of local elements in the CSysVector
419 */
420 inline unsigned long GetLocSize() const { return nElm; }
421
422 /*!
423 * \brief return the number of local elements in the CSysVector without ghost cells
424 */
425 inline unsigned long GetNElmDomain() const { return nElmDomain; }
426
427 /*!
428 * \brief return the number of variables at each block (typically number per node)
429 */
430 inline unsigned long GetNVar() const { return nVar; }
431
432 /*!
433 * \brief return the number of blocks (typically number of nodes locally)
434 */
435 inline unsigned long GetNBlk() const { return nElm / nVar; }
436
437 /*!
438 * \brief return the number of blocks (typically number of nodes locally)
439 */
440 inline unsigned long GetNBlkDomain() const { return nElmDomain / nVar; }
441
442 /*!
443 * \brief Access operator with assignment permitted.
444 * \param[in] i - Local index to access.
445 * \return Value at position i.
446 */
447 inline ScalarType& operator[](unsigned long i) { return vec_val[i]; }
448 inline const ScalarType& operator[](unsigned long i) const { return vec_val[i]; }
449
450 /*!
451 * \brief Iterators for range for loops.
452 */
453 inline const ScalarType* begin() const { return vec_val; }
454 inline const ScalarType* end() const { return vec_val + nElm; }
455
456 /*!
457 * \brief Access operator with assignment permitted block version.
458 * \param[in] iPoint - Index of block.
459 * \param[in] iVar - Index of variable.
460 * \return Value at position (i,j).
461 */
462 inline ScalarType& operator()(unsigned long iPoint, unsigned long iVar) { return vec_val[iPoint * nVar + iVar]; }
463 inline const ScalarType& operator()(unsigned long iPoint, unsigned long iVar) const {
464 return vec_val[iPoint * nVar + iVar];
465 }
466
467 /*!
468 * \brief Assignment operator from another vector.
469 * \note Does not resize as it is meant for use in parallel.
470 * \param[in] other - Another vector.
471 */
473#ifdef SU2_ENABLE_CUDA_KERNELS
474 if constexpr (su2_gpu_capable_v<ScalarType>) {
475 if (VecExpr::UseDeviceExpressions()) return AssignDevice<VecExpr::DeviceAssignOp::Assign>(other);
476 }
477#endif
479 for (auto i = 0ul; i < nElm; ++i) vec_val[i] = other.vec_val[i];
481 return *this;
482 }
483
484 /*!
485 * \brief Compound assignement operations with scalars and expressions.
486 * \param[in] val/expr - Scalar value or expression.
487 */
488#define MAKE_COMPOUND(OP, ASSIGN_OP) \
489 CSysVector& operator OP(ScalarType val) { \
490 if constexpr (su2_gpu_capable_v<ScalarType>) { \
491 if (VecExpr::UseDeviceExpressions()) return AssignDevice<ASSIGN_OP>(val); \
492 } \
493 CSYSVEC_PARFOR \
494 for (auto i = 0ul; i < nElm; ++i) vec_val[i] OP val; \
495 END_CSYSVEC_PARFOR \
496 return *this; \
497 } \
498 template <class T> \
499 CSysVector& operator OP(const VecExpr::CVecExpr<T, ScalarType>& expr) { \
500 if constexpr (su2_gpu_capable_v<ScalarType>) { \
501 if (VecExpr::UseDeviceExpressions()) return AssignDevice<ASSIGN_OP>(expr); \
502 } \
503 CSYSVEC_PARFOR \
504 for (auto i = 0ul; i < nElm; ++i) vec_val[i] OP expr.derived()[i]; \
505 END_CSYSVEC_PARFOR \
506 return *this; \
507 }
509 MAKE_COMPOUND(+=, VecExpr::DeviceAssignOp::Add)
510 MAKE_COMPOUND(-=, VecExpr::DeviceAssignOp::Subtract)
511 MAKE_COMPOUND(*=, VecExpr::DeviceAssignOp::Multiply)
512 MAKE_COMPOUND(/=, VecExpr::DeviceAssignOp::Divide)
513#undef MAKE_COMPOUND
514
515 /*!
516 * \brief Sets to zero all the entries of the vector.
517 */
518 inline void SetValZero(void) { *this = ScalarType(0); }
519
520 /*!
521 * \brief Dot product between "this" and an expression.
522 * \param[in] expr - Expression.
523 * \return Result of dot product
524 */
525 template <class T>
526 ScalarType dot(const VecExpr::CVecExpr<T, ScalarType>& expr) const {
527#ifdef SU2_ENABLE_CUDA_KERNELS
528 if constexpr (su2_gpu_capable_v<ScalarType>) {
529 using DeviceExpr = std::remove_cv_t<VecExpr::remove_reference_t<T>>;
530 static_assert(std::is_same_v<DeviceExpr, CSysVector>,
531 "On the device the dot product needs a real device pointer (dotGPU takes a "
532 "materialized vector, not an expression template), so it only takes vectors. "
533 "Assign the expression to a vector first.");
535 /*--- dotGPU reduces over MPI, which has to happen once for the team, so the result
536 * is published through the same scratch slot the host reduction below uses. ---*/
537 SU2_DEVICE_REGION(dot_scratch[0] = dotGPU(expr.derived());)
538 return dot_scratch[0];
539 }
540 }
541#endif
542
543 /*--- All threads get the same "view" of the vectors. ---*/
545
546 /*--- Local dot product for each thread. ---*/
547 ScalarType sum = 0.0;
548
550 for (auto i = 0ul; i < nElmDomain; ++i) {
551 sum += vec_val[i] * expr.derived()[i];
552 }
554
555 dot_scratch[omp_get_thread_num()] = sum;
556
558 /*--- Reduce over all threads in an ordered way to ensure a deterministic result. ---*/
559 for (int i = 1; i < omp_get_num_threads(); ++i) sum += dot_scratch[i];
560
561 /*--- Reduce across all mpi ranks, only the master thread communicates. ---*/
562 const auto mpi_type = (sizeof(ScalarType) < sizeof(double)) ? MPI_FLOAT : MPI_DOUBLE;
563 SelectMPIWrapper<ScalarType>::W::Allreduce(&sum, &dot_scratch[0], 1, mpi_type, MPI_SUM, SU2_MPI::GetComm());
564 }
565 /*--- Make view of result consistent across threads. ---*/
567
568 return dot_scratch[0];
569 }
570
571 /*!
572 * \brief Computes the product of V^T W efficiencly, where V and W are tall matrices stored as vectors of CSysVector.
573 * \param[in] V - Tall matrix.
574 * \param[in] i0 - First column of V to consider.
575 * \param[in] n - Number of columns to consider from V starting at i0.
576 * \param[in] W - Tall matrix.
577 * \param[in] m - Number of columns to consider from W.
578 * \return n by m matrix with the result of the product.
579 */
580 static const su2matrix<ScalarType>& multiDot(const std::vector<CSysVector>& V, size_t i0, size_t n,
581 const std::vector<CSysVector>& W, size_t m);
582
583 /*!
584 * \brief Squared L2 norm of the vector (via dot with self).
585 * \return Squared L2 norm.
586 */
587 inline ScalarType squaredNorm() const { return dot(*this); }
588
589 /*!
590 * \brief L2 norm of the vector.
591 * \return L2 norm.
592 */
593 inline ScalarType norm() const { return sqrt(squaredNorm()); }
594
595 /*!
596 * \brief Get pointer to a block.
597 * \param[in] iPoint - Index of block.
598 * \return Pointer to start of block.
599 */
600 inline ScalarType* GetBlock(unsigned long iPoint) { return &vec_val[iPoint * nVar]; }
601 inline const ScalarType* GetBlock(unsigned long iPoint) const { return &vec_val[iPoint * nVar]; }
602
603 /*!
604 * \brief Set the values to zero for one block.
605 * \param[in] iPoint - Index of the block being set to zero.
606 */
607 inline void SetBlock_Zero(unsigned long iPoint) {
608 for (auto iVar = 0ul; iVar < nVar; iVar++) vec_val[iPoint * nVar + iVar] = 0.0;
609 }
610
611 /*!
612 * \brief Set "block" to the vector.
613 * \note Template param Overwrite can be set to false to update existing values.
614 * \param[in] iPoint - index of the point where set the residual.
615 * \param[in] block - Value to set to the residual.
616 * \param[in] alpha - Scale factor (axpy-type operation).
617 */
618 template <class VectorType, bool Overwrite = true>
619 FORCEINLINE void SetBlock(unsigned long iPoint, const VectorType& block, ScalarType alpha = 1) {
620 if (Overwrite) {
621 for (auto i = 0ul; i < nVar; ++i) vec_val[iPoint * nVar + i] = alpha * block[i];
622 } else {
623 for (auto i = 0ul; i < nVar; ++i) vec_val[iPoint * nVar + i] += alpha * block[i];
624 }
625 }
626
627 /*!
628 * \brief Add "block" to the vector, see SetBlock.
629 */
630 template <class VectorType>
631 FORCEINLINE void AddBlock(unsigned long iPoint, const VectorType& block, ScalarType alpha = 1) {
632 SetBlock<VectorType, false>(iPoint, block, alpha);
633 }
634
635 /*!
636 * \brief Subtract "block" from the vector, see AddBlock.
637 */
638 template <class VectorType>
639 FORCEINLINE void SubtractBlock(unsigned long iPoint, const VectorType& block) {
640 AddBlock(iPoint, block, -1);
641 }
642
643 /*!
644 * \brief Add to iPoint, subtract from jPoint.
645 */
646 template <class VectorType>
647 FORCEINLINE void UpdateBlocks(unsigned long iPoint, unsigned long jPoint, const VectorType& block,
648 ScalarType alpha = 1) {
649 AddBlock(iPoint, block, alpha);
650 AddBlock(jPoint, block, -alpha);
651 }
652
653 /*!
654 * \brief Vectorized version of SetBlock, sets multiple iPoint's.
655 * \param[in] iPoint - SIMD integer, the positions to update.
656 * \param[in] vector - Vector of SIMD scalars.
657 * \param[in] mask - Optional scale factor (axpy type operation).
658 * \note Nothing is updated if the mask is 0.
659 */
660 template <size_t N, class T, class VecTypeSIMD, class F = ScalarType>
661 FORCEINLINE void SetBlock(simd::Array<T, N> iPoint, const VecTypeSIMD& vector, simd::Array<F, N> mask = 1) {
662 /*--- "Transpose" and scale input vector. ---*/
663 constexpr size_t nVar = VecTypeSIMD::StaticSize;
664 assert(nVar == this->nVar);
665 ScalarType vec[N][nVar];
666 UnpackBlock(vector, mask, vec);
667
668 /*--- Update one by one skipping if mask is 0. ---*/
669 for (size_t k = 0; k < N; ++k) {
670 if (mask[k] == 0) continue;
672 for (size_t i = 0; i < nVar; ++i) vec_val[iPoint[k] * nVar + i] = vec[k][i];
673 }
674 }
675
676 /*!
677 * \brief Vectorized version of UpdateBlocks, updates multiple i/jPoint's.
678 * \note See SIMD overload of SetBlock.
679 */
680 template <size_t N, class T, class VecTypeSIMD, class F = ScalarType>
681 FORCEINLINE void UpdateBlocks(simd::Array<T, N> iPoint, simd::Array<T, N> jPoint, const VecTypeSIMD& vector,
682 simd::Array<F, N> mask = 1) {
683 /*--- "Transpose" and scale input vector. ---*/
684 constexpr size_t nVar = VecTypeSIMD::StaticSize;
685 assert(nVar == this->nVar);
686 ScalarType vec[N][nVar];
687 UnpackBlock(vector, mask, vec);
688
689 /*--- Update one by one skipping if mask is 0. ---*/
690 for (size_t k = 0; k < N; ++k) {
691 if (mask[k] == 0) continue;
693 for (size_t i = 0; i < nVar; ++i) {
694 vec_val[iPoint[k] * nVar + i] += vec[k][i];
695 vec_val[jPoint[k] * nVar + i] -= vec[k][i];
696 }
697 }
698 }
699};
700
701namespace VecExpr {
702
703template <class Scalar>
705 : data(UseDeviceExpressions() ? vector.GetDevicePointer() : vector.GetHostPointer()) {}
706
707} // namespace VecExpr
708
709#undef CSYSVEC_PARFOR
710#undef END_CSYSVEC_PARFOR
CNewtonIntegration::Scalar Scalar
Definition CNewtonIntegration.cpp:31
#define MAKE_COMPOUND(OP, ASSIGN_OP)
Compound assignement operations with scalars and expressions.
Definition CSysVector.hpp:488
#define END_CSYSVEC_PARFOR
Definition CSysVector.hpp:86
#define SU2_DEVICE_REGION(...)
Brackets device work so that it is issued by a single thread with the whole team synchronized before ...
Definition CSysVector.hpp:100
#define BEGIN_SU2_DEVICE_REGION
Definition CSysVector.hpp:101
#define END_SU2_DEVICE_REGION
Definition CSysVector.hpp:102
#define CSYSVEC_PARFOR
OpenMP worksharing construct used in CSysVector for loops.
Definition CSysVector.hpp:85
constexpr bool su2_gpu_capable_v
True for the plain floating-point scalar types the GPU vector kernels (CSysVectorGPU....
Definition CSysVector.hpp:64
Header file containing universal functions that provide basic and essential utilities for other GPU p...
#define gpuErrChk(ans)
Definition GPUComms.cuh:58
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
static Comm GetComm()
Definition mpi_structure.hpp:530
static void Allreduce(const void *sendbuf, void *recvbuf, int count, Datatype datatype, Op op, Comm comm)
Definition mpi_structure.hpp:570
Class for holding and manipulating vectors needed by linear solvers.
Definition CSysVector.hpp:195
CSysVector(unsigned long size, const ScalarType *u_array)
Construct from array.
Definition CSysVector.hpp:318
void DtHTransfer(bool trigger=true) const
Performs the memory copy from device to host.
Definition CSysVectorGPU.cu:200
const ScalarType & operator()(unsigned long iPoint, unsigned long iVar) const
Definition CSysVector.hpp:463
CSysVector & operator=(const CSysVector &other)
Assignment operator from another vector.
Definition CSysVector.hpp:472
unsigned long GetNElmDomain() const
return the number of local elements in the CSysVector without ghost cells
Definition CSysVector.hpp:425
void SetBlock(simd::Array< T, N > iPoint, const VecTypeSIMD &vector, simd::Array< F, N > mask=1)
Vectorized version of SetBlock, sets multiple iPoint's.
Definition CSysVector.hpp:661
void swap(CSysVector &other)
Swap contents with another vector.
Definition CSysVector.hpp:341
void Initialize(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, ScalarType val=0.0)
Initialize the class with a scalar.
Definition CSysVector.hpp:358
unsigned long GetNBlkDomain() const
return the number of blocks (typically number of nodes locally)
Definition CSysVector.hpp:440
ScalarType & operator[](unsigned long i)
Access operator with assignment permitted.
Definition CSysVector.hpp:447
unsigned long GetNBlk() const
return the number of blocks (typically number of nodes locally)
Definition CSysVector.hpp:435
CSysVector(const CSysVector &u)
Copy constructor of the class.
Definition CSysVector.hpp:336
~CSysVector()
Destructor.
Definition CSysVector.cpp:159
CSysVector(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, ScalarType val=0.0)
Construct from size and value (block version).
Definition CSysVector.hpp:309
void UpdateBlocks(simd::Array< T, N > iPoint, simd::Array< T, N > jPoint, const VecTypeSIMD &vector, simd::Array< F, N > mask=1)
Vectorized version of UpdateBlocks, updates multiple i/jPoint's.
Definition CSysVector.hpp:681
ScalarType norm() const
L2 norm of the vector.
Definition CSysVector.hpp:593
ScalarType * GetDevicePointer() const
return device pointer that points to the CSysVector values in GPU memory
Definition CSysVector.hpp:409
ScalarType squaredNorm() const
Squared L2 norm of the vector (via dot with self).
Definition CSysVector.hpp:587
void HtDTransfer(bool trigger=true) const
Performs the memory copy from host to device.
Definition CSysVectorGPU.cu:193
void Initialize(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, const ScalarType *ptr)
Initialize the class with an array.
Definition CSysVector.hpp:370
const ScalarType * GetHostPointer() const
return host pointer that points to the CSysVector values, counterpart of GetDevicePointer
Definition CSysVector.hpp:415
CSysVector()=default
Required by CVecExpr.
void SubtractBlock(unsigned long iPoint, const VectorType &block)
Subtract "block" from the vector, see AddBlock.
Definition CSysVector.hpp:639
ScalarType * GetBlock(unsigned long iPoint)
Get pointer to a block.
Definition CSysVector.hpp:600
static const su2matrix< ScalarType > & multiDot(const std::vector< CSysVector > &V, size_t i0, size_t n, const std::vector< CSysVector > &W, size_t m)
Computes the product of V^T W efficiencly, where V and W are tall matrices stored as vectors of CSysV...
Definition CSysVector.cpp:74
unsigned long GetLocSize() const
return the number of local elements in the CSysVector
Definition CSysVector.hpp:420
ScalarType & operator()(unsigned long iPoint, unsigned long iVar)
Access operator with assignment permitted block version.
Definition CSysVector.hpp:462
ScalarType dot(const VecExpr::CVecExpr< T, ScalarType > &expr) const
Dot product between "this" and an expression.
Definition CSysVector.hpp:526
void SetBlock_Zero(unsigned long iPoint)
Set the values to zero for one block.
Definition CSysVector.hpp:607
void SetValZero(void)
Sets to zero all the entries of the vector.
Definition CSysVector.hpp:518
void AddBlock(unsigned long iPoint, const VectorType &block, ScalarType alpha=1)
Add "block" to the vector, see SetBlock.
Definition CSysVector.hpp:631
const ScalarType * end() const
Definition CSysVector.hpp:454
const ScalarType & operator[](unsigned long i) const
Definition CSysVector.hpp:448
void UpdateBlocks(unsigned long iPoint, unsigned long jPoint, const VectorType &block, ScalarType alpha=1)
Add to iPoint, subtract from jPoint.
Definition CSysVector.hpp:647
void PassiveCopy(const CSysVector< T > &other)
Set our values (resizing if required) by copying from other, the derivative information is lost.
Definition CSysVector.hpp:379
unsigned long GetNVar() const
return the number of variables at each block (typically number per node)
Definition CSysVector.hpp:430
void SetBlock(unsigned long iPoint, const VectorType &block, ScalarType alpha=1)
Set "block" to the vector.
Definition CSysVector.hpp:619
static constexpr bool StoreAsRef
Definition CSysVector.hpp:283
const ScalarType * begin() const
Iterators for range for loops.
Definition CSysVector.hpp:453
const ScalarType * GetBlock(unsigned long iPoint) const
Definition CSysVector.hpp:601
CSysVector(unsigned long numBlk, unsigned long numBlkDomain, unsigned long numVar, const ScalarType *u_array)
Constructor from array (block version).
Definition CSysVector.hpp:327
CSysVector(unsigned long size, ScalarType val=0.0)
Construct from size and value.
Definition CSysVector.hpp:300
Expression class to broadcast a scalar value. Allows implementing "vector-scalar" operations re-using...
Definition vector_expressions.hpp:75
Base vector expression class.
Definition vector_expressions.hpp:58
const Derived & derived() const
Cast the expression to Derived, usually to allow evaluation via operator[].
Definition vector_expressions.hpp:63
How a CSysVector is captured inside an expression: a bare pointer to whichever storage the expression...
Definition CSysVector.hpp:133
CVectorView(const CSysVector< Scalar > &vector)
Definition CSysVector.hpp:704
static constexpr bool StoreAsRef
Definition CSysVector.hpp:138
const Scalar & operator[](size_t i) const
Definition CSysVector.hpp:142
A simple SIMD type relying on implicit vectorization, i.e. done by the compiler, explicitly vectorize...
Definition vectorization.hpp:89
#define SU2_CUDA_HOST_DEVICE
Definition code_config.hpp:57
#define FORCEINLINE
Definition code_config.hpp:44
FORCEINLINE ARRAY_T sqrt(const ARRAY_T &x)
Definition special_vectorization.hpp:116
typename store_type< T >::type store_t
Definition vector_expressions.hpp:109
#define MPI_FLOAT
Definition mpi_structure.hpp:483
#define MPI_SUM
Definition mpi_structure.hpp:486
#define MPI_DOUBLE
Definition mpi_structure.hpp:484
passivedouble GetValue(const su2double &data)
Get the (primitive) value of the datatype (needs to be specialized for active types).
Definition datatype_structure.hpp:113
Definition CSysVector.hpp:104
bool UseDeviceExpressions()
Whether vector expressions are currently evaluated on the device.
Definition CSysVector.hpp:119
void SetUseDeviceExpressions(bool)
Definition CSysVector.hpp:120
void AssignDeviceExpression(Scalar *data, unsigned long size, const CVecExpr< T, Scalar > &expr)
DeviceAssignOp
Definition CSysVector.hpp:106
#define BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS
Definition omp_structure.hpp:187
constexpr int omp_get_num_threads()
Number of threads in current team.
Definition omp_structure.hpp:75
#define END_SU2_OMP_SAFE_GLOBAL_ACCESS
Definition omp_structure.hpp:192
#define SU2_OMP_BARRIER
Definition omp_structure.hpp:142
#define SU2_OMP_SAFE_GLOBAL_ACCESS(...)
Definition omp_structure.hpp:197
constexpr int omp_get_thread_num()
Index of current thread, akin to MPI rank.
Definition omp_structure.hpp:85
#define SU2_OMP_SIMD
Definition omp_structure.hpp:125
#define SU2_OMP_SIMD_IF_NOT_AD
Definition omp_structure.hpp:129
@ V
Menter k-w SST model with vorticity production terms.
@ W
W-cycle multigrid solver.
Definition vector_expressions.hpp:105
Expression templates for vector types with coefficient-wise operations.