Documentation 6b54b78464
Loading...
Searching...
No Matches
blas_structure.hpp
Go to the documentation of this file.
1/*!
2 * \file blas_structure.hpp
3 * \brief Include files and headers of the functions for matrix and vector
4 operations, which are typically found in the BLAS libraries.
5 The functions are in the <i>blass_structure.cpp</i> file.
6 * \author E. van der Weide
7 * \version 8.5.0 "Harrier"
8 *
9 * SU2 Project Website: https://su2code.github.io
10 *
11 * The SU2 Project is maintained by the SU2 Foundation
12 * (http://su2foundation.org)
13 *
14 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
15 *
16 * SU2 is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * SU2 is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
28 */
29
30#pragma once
31
32class CConfig;
33
34/*!
35 * \class CBlasStructure
36 * \ingroup BLAS
37 * \brief Class, which serves as an interface to the BLAS functionalities needed.
38 * \author: E. van der Weide
39 * \version 8.5.0 "Harrier"
40 */
42 public:
43 /*!
44 * \brief Constructor of the class. Initialize the constant member variables.
45 */
46 CBlasStructure(void);
47
48 /*!
49 * \brief Function, which carries out a dense matrix product. It is a
50 limited version of the BLAS gemm functionality..
51 * \param[in] M - Number of rows of A and C.
52 * \param[in] N - Number of columns of B and C.
53 * \param[in] K - Number of columns of A and number of rows of B.
54 * \param[in] A - Input matrix in the multiplication.
55 * \param[in] B - Input matrix in the multiplication.
56 * \param[out] C - Result of the matrix product A*B.
57 */
58 void gemm(const int M, const int N, const int K, const su2double* A, const su2double* B, su2double* C,
59 const CConfig* config);
60
61 /*!
62 * \brief Function, which carries out a dense matrix vector product
63 y = A x. It is a limited version of the BLAS gemv functionality.
64 * \param[in] M - Number of rows of A and size of y.
65 * \param[in] N - Number of columns of A and size of x.
66 * \param[in] A - Input matrix in the multiplication, row major order.
67 * \param[in] x - Input vector in the multiplication.
68 * \param[out] y - Result of the product A x.
69 */
70 void gemv(const int M, const int N, const su2double* A, const su2double* x, su2double* y);
71
72 /*!
73 * \brief Function, to carry out the axpy operation, i.e y += a*x.
74 * \param[in] n - Number of elements in the vectors x and y.
75 * \param[in] a - Specifies the scalar a.
76 * \param[in] x - Array, which must be added, size of x must be
77 at least 1 + (n-1)*abs(incx).
78 * param[in] incx - Specifies the increment of x.
79 * param[inout] y - Vector to be updated, size of y must be
80 at least 1 + (n-1)*abs(incy).
81 * param[in] incy - Specifies the increment of y.
82 */
83 void axpy(const int n, const su2double a, const su2double* x, const int incx, su2double* y, const int incy);
84
85 /*!
86 * \brief Invert a square matrix.
87 * \param[in] M - Size.
88 * \param[in,out] mat - Matrix, and inverse on exit.
89 */
90 template <class Mat>
91 static void inverse(const int M, Mat& mat) {
92 using Scalar = typename Mat::Scalar;
93
94 /*--- Copy the data from A into the augmented matrix and initialize mat with the identity. ---*/
95 Mat aug = mat;
96 mat = Scalar(0);
97 for (int j = 0; j < M; ++j) mat(j, j) = 1;
98
99 /*--- Outer loop of the Gauss-Jordan elimination. ---*/
100 for (int j = 0; j < M; ++j) {
101 /*--- Find the pivot in the current column. ---*/
102 int jj = j;
103 Scalar valMax = fabs(aug(j, j));
104 for (int i = j + 1; i < M; ++i) {
105 Scalar val = fabs(aug(i, j));
106 if (val > valMax) {
107 jj = i;
108 valMax = val;
109 }
110 }
111
112 /*--- Swap the rows j and jj, if needed. ---*/
113 if (jj > j) {
114 for (int k = j; k < M; ++k) std::swap(aug(j, k), aug(jj, k));
115 for (int k = 0; k < M; ++k) std::swap(mat(j, k), mat(jj, k));
116 }
117
118 /*--- Performing row operations to form required identity
119 matrix out of the input matrix. ---*/
120 for (int i = 0; i < M; ++i) {
121 if (i == j) continue;
122 valMax = aug(i, j) / aug(j, j);
123 for (int k = j; k < M; ++k) aug(i, k) -= valMax * aug(j, k);
124 for (int k = 0; k < M; ++k) mat(i, k) -= valMax * mat(j, k);
125 }
126
127 valMax = 1.0 / aug(j, j);
128 for (int k = j; k < M; ++k) aug(j, k) *= valMax;
129 for (int k = 0; k < M; ++k) mat(j, k) *= valMax;
130 }
131 }
132
133 /*!
134 * \brief tred2
135 * Author:
136 *
137 * Original FORTRAN77 version by Smith, Boyle, Dongarra, Garbow, Ikebe,
138 * Klema, Moler.
139 * C++ version by Aashwin Mishra and Jayant Mukhopadhaya.
140 *
141 * Reference:
142 *
143 * Martin, Reinsch, Wilkinson,
144 * TRED2,
145 * Numerische Mathematik,
146 * Volume 11, pages 181-195, 1968.
147 *
148 * James Wilkinson, Christian Reinsch,
149 * Handbook for Automatic Computation,
150 * Volume II, Linear Algebra, Part 2,
151 * Springer, 1971,
152 * ISBN: 0387054146,
153 * LC: QA251.W67.
154 *
155 * Brian Smith, James Boyle, Jack Dongarra, Burton Garbow,
156 * Yasuhiko Ikebe, Virginia Klema, Cleve Moler,
157 * Matrix Eigensystem Routines, EISPACK Guide,
158 * Lecture Notes in Computer Science, Volume 6,
159 * Springer Verlag, 1976,
160 * ISBN13: 978-3540075462,
161 * LC: QA193.M37
162 *
163 * \param[in,out] V: matrix that needs to be decomposed
164 * \param[in,out] d: holds eigenvalues
165 * \param[in,out] e: work vector
166 * \param[in] n: order of matrix V
167 */
168 template <class Mat, class Vec, class W>
169 static void tred2(Mat& V, Vec& d, W& e, int n) {
170 using Scalar = typename std::decay<decltype(e[0])>::type;
171
172 int i, j, k;
173
174 for (j = 0; j < n; j++) {
175 d[j] = V[n - 1][j];
176 }
177
178 /* Householder reduction to tridiagonal form. */
179
180 for (i = n - 1; i > 0; i--) {
181 /* Scale to avoid under/overflow. */
182
183 Scalar scale = 0.0;
184 Scalar h = 0.0;
185 for (k = 0; k < i; k++) {
186 scale = scale + fabs(d[k]);
187 }
188 if (scale == 0.0) {
189 e[i] = d[i - 1];
190 for (j = 0; j < i; j++) {
191 d[j] = V[i - 1][j];
192 V[i][j] = 0.0;
193 V[j][i] = 0.0;
194 }
195 } else {
196 /* Generate Householder vector. */
197
198 for (k = 0; k < i; k++) {
199 d[k] /= scale;
200 h += d[k] * d[k];
201 }
202 Scalar f = d[i - 1];
203 Scalar g = sqrt(h);
204 if (f > 0) {
205 g = -g;
206 }
207 e[i] = scale * g;
208 h = h - f * g;
209 d[i - 1] = f - g;
210 for (j = 0; j < i; j++) {
211 e[j] = 0.0;
212 }
213
214 /* Apply similarity transformation to remaining columns. */
215
216 for (j = 0; j < i; j++) {
217 f = d[j];
218 V[j][i] = f;
219 g = e[j] + V[j][j] * f;
220 for (k = j + 1; k <= i - 1; k++) {
221 g += V[k][j] * d[k];
222 e[k] += V[k][j] * f;
223 }
224 e[j] = g;
225 }
226 f = 0.0;
227 for (j = 0; j < i; j++) {
228 e[j] /= h;
229 f += e[j] * d[j];
230 }
231 Scalar hh = f / (h + h);
232 for (j = 0; j < i; j++) {
233 e[j] -= hh * d[j];
234 }
235 for (j = 0; j < i; j++) {
236 f = d[j];
237 g = e[j];
238 for (k = j; k <= i - 1; k++) {
239 V[k][j] -= (f * e[k] + g * d[k]);
240 }
241 d[j] = V[i - 1][j];
242 V[i][j] = 0.0;
243 }
244 }
245 d[i] = h;
246 }
247
248 /* Accumulate transformations. */
249
250 for (i = 0; i < n - 1; i++) {
251 V[n - 1][i] = V[i][i];
252 V[i][i] = 1.0;
253 Scalar h = d[i + 1];
254 if (h != 0.0) {
255 for (k = 0; k <= i; k++) {
256 d[k] = V[k][i + 1] / h;
257 }
258 for (j = 0; j <= i; j++) {
259 Scalar g = 0.0;
260 for (k = 0; k <= i; k++) {
261 g += V[k][i + 1] * V[k][j];
262 }
263 for (k = 0; k <= i; k++) {
264 V[k][j] -= g * d[k];
265 }
266 }
267 }
268 for (k = 0; k <= i; k++) {
269 V[k][i + 1] = 0.0;
270 }
271 }
272 for (j = 0; j < n; j++) {
273 d[j] = V[n - 1][j];
274 V[n - 1][j] = 0.0;
275 }
276 V[n - 1][n - 1] = 1.0;
277 e[0] = 0.0;
278 }
279
280 /*!
281 * \brief tql2
282 * Author:
283 *
284 * Original FORTRAN77 version by Smith, Boyle, Dongarra, Garbow, Ikebe,
285 * Klema, Moler.
286 * C++ version by Aashwin Mishra and Jayant Mukhopadhaya.
287 *
288 * Reference:
289 *
290 * Bowdler, Martin, Reinsch, Wilkinson,
291 * TQL2,
292 * Numerische Mathematik,
293 * Volume 11, pages 293-306, 1968.
294 *
295 * James Wilkinson, Christian Reinsch,
296 * Handbook for Automatic Computation,
297 * Volume II, Linear Algebra, Part 2,
298 * Springer, 1971,
299 * ISBN: 0387054146,
300 * LC: QA251.W67.
301 *
302 * Brian Smith, James Boyle, Jack Dongarra, Burton Garbow,
303 * Yasuhiko Ikebe, Virginia Klema, Cleve Moler,
304 * Matrix Eigensystem Routines, EISPACK Guide,
305 * Lecture Notes in Computer Science, Volume 6,
306 * Springer Verlag, 1976,
307 * ISBN13: 978-3540075462,
308 * LC: QA193.M37
309 *
310 * \param[in,out] V: matrix that will hold the eigenvectors
311 * \param[in,out] d: array that will hold the ordered eigenvalues
312 * \param[in,out] e: work vector
313 * \param[in] n: order of matrix V
314 */
315 template <class Mat, class Vec, class W>
316 static void tql2(Mat& V, Vec& d, W& e, int n) {
317 using Scalar = typename std::decay<decltype(e[0])>::type;
318
319 int i, j, k, l;
320 for (i = 1; i < n; i++) {
321 e[i - 1] = e[i];
322 }
323 e[n - 1] = 0.0;
324
325 Scalar f = 0.0;
326 Scalar tst1 = 0.0;
327 Scalar eps = pow(2.0, -52.0);
328 for (l = 0; l < n; l++) {
329 /* Find small subdiagonal element */
330
331 tst1 = max(tst1, (fabs(d[l]) + fabs(e[l])));
332 int m = l;
333 while (m < n) {
334 if (fabs(e[m]) <= eps * tst1) {
335 break;
336 }
337 m++;
338 }
339
340 /* If m == l, d[l] is an eigenvalue, */
341 /* otherwise, iterate. */
342
343 if (m > l) {
344 int iter = 0;
345 do {
346 iter = iter + 1; /* (Could check iteration count here.) */
347
348 /* Compute implicit shift */
349
350 Scalar g = d[l];
351 Scalar p = (d[l + 1] - g) / (2.0 * e[l]);
352 Scalar r = sqrt(p * p + 1.0);
353 if (p < 0) {
354 r = -r;
355 }
356 d[l] = e[l] / (p + r);
357 d[l + 1] = e[l] * (p + r);
358 Scalar dl1 = d[l + 1];
359 Scalar h = g - d[l];
360 for (i = l + 2; i < n; i++) {
361 d[i] -= h;
362 }
363 f = f + h;
364
365 /* Implicit QL transformation. */
366
367 p = d[m];
368 Scalar c = 1.0;
369 Scalar c2 = c;
370 Scalar c3 = c;
371 Scalar el1 = e[l + 1];
372 Scalar s = 0.0;
373 Scalar s2 = 0.0;
374 for (i = m - 1; i >= l; i--) {
375 c3 = c2;
376 c2 = c;
377 s2 = s;
378 g = c * e[i];
379 h = c * p;
380 r = sqrt(p * p + e[i] * e[i]);
381 e[i + 1] = s * r;
382 s = e[i] / r;
383 c = p / r;
384 p = c * d[i] - s * g;
385 d[i + 1] = h + s * (c * g + s * d[i]);
386
387 /* Accumulate transformation. */
388
389 for (k = 0; k < n; k++) {
390 h = V[k][i + 1];
391 V[k][i + 1] = s * V[k][i] + c * h;
392 V[k][i] = c * V[k][i] - s * h;
393 }
394 }
395 p = -s * s2 * c3 * el1 * e[l] / dl1;
396 e[l] = s * p;
397 d[l] = c * p;
398
399 /* Check for convergence. */
400
401 } while (fabs(e[l]) > eps * tst1);
402 }
403 d[l] = d[l] + f;
404 e[l] = 0.0;
405 }
406
407 /* Sort eigenvalues and corresponding vectors. */
408
409 for (i = 0; i < n - 1; i++) {
410 k = i;
411 Scalar p = d[i];
412 for (j = i + 1; j < n; j++) {
413 if (d[j] < p) {
414 k = j;
415 p = d[j];
416 }
417 }
418 if (k != i) {
419 d[k] = d[i];
420 d[i] = p;
421 for (j = 0; j < n; j++) {
422 p = V[j][i];
423 V[j][i] = V[j][k];
424 V[j][k] = p;
425 }
426 }
427 }
428 }
429
430 /*!
431 * \brief Decomposes the symmetric matrix A_ij, into eigenvectors and eigenvalues
432 * \param[in] A_i: symmetric matrix to be decomposed
433 * \param[in,out] Eig_Vec: stores the eigenvectors
434 * \param[in,out] Eig_Val: stores the eigenvalues
435 * \param[in] n: order of matrix A_ij
436 * \param[in,out] e: work vector
437 */
438 template <class Mat, class Vec, class W>
439 static void EigenDecomposition(const Mat& A_ij, Mat& Eig_Vec, Vec& Eig_Val, int n, W& e) {
440 for (int iDim = 0; iDim < n; iDim++) {
441 e[iDim] = 0.0;
442 for (int jDim = 0; jDim < n; jDim++) {
443 Eig_Vec[iDim][jDim] = A_ij[iDim][jDim];
444 }
445 }
446 tred2(Eig_Vec, Eig_Val, e, n);
447 tql2(Eig_Vec, Eig_Val, e, n);
448 }
449
450 /*!
451 * \brief Recomposes the eigenvectors and eigenvalues into a matrix
452 * \param[out] A_ij: recomposed matrix
453 * \param[in] Eig_Vec: eigenvectors
454 * \param[in] Eig_Val: eigenvalues
455 * \param[in] n: order of matrix A_ij
456 */
457 template <class Mat, class Vec>
458 static void EigenRecomposition(Mat& A_ij, const Mat& Eig_Vec, const Vec& Eig_Val, int n) {
459 for (int i = 0; i < n; i++) {
460 for (int j = 0; j < n; j++) {
461 A_ij[i][j] = 0.0;
462 for (int k = 0; k < n; k++) A_ij[i][j] += Eig_Vec[i][k] * Eig_Val[k] * Eig_Vec[j][k];
463 }
464 }
465 }
466
467 /*!
468 * \brief Algorithm to solve a linear system with a tridiagonal matrix.
469 * \param[in] lower - lower diagonal
470 * \param[in] main - main diagonal
471 * \param[in,out] upper - upper diagonal (modified on exit)
472 * \param[in,out] rhs - right hand side on entry, solution on exit
473 * \note Same size for all vectors. Use row index for lower and upper vector (e.g. lower[0] does not matter).
474 */
475 template <class Vec, class Scalar = su2double>
476 static void tdma(const Vec& lower, const Vec& main, Vec& upper, Vec& rhs) {
477 const int N = main.size();
478
479 upper[0] /= main[0];
480 rhs[0] /= main[0];
481
482 for (int i = 1; i < N; i++) {
483 const Scalar denom = 1.0 / (main[i] - lower[i] * upper[i - 1]);
484 upper[i] *= denom;
485 rhs[i] = (rhs[i] - lower[i] * rhs[i - 1]) * denom;
486 }
487
488 for (int i = N - 2; i >= 0; i--) rhs[i] -= upper[i] * rhs[i + 1];
489 }
490
491 private:
492#if !(defined(HAVE_BLAS) || defined(HAVE_MKL)) || (defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE))
493 /* Blocking parameters for the outer kernel. We multiply mc x kc blocks of
494 the matrix A with kc x nc panels of the matrix B (this approach is referred
495 to as `gebp` in the literature). */
496 const int mc;
497 const int kc;
498 const int nc;
499
500 /*!
501 * \brief Function, which perform the implementation of the gemm functionality.
502 * \param[in] m - Number of rows of a and c.
503 * \param[in] n - Number of columns of b and c.
504 * \param[in] k - Number of columns of a and number of rows of b.
505 * \param[in] a - Input matrix in the multiplication.
506 * \param[in] b - Input matrix in the multiplication.
507 * \param[out] c - Result of the matrix product a*b.
508 */
509 void gemm_imp(const int m, const int n, const int k, const su2double* a, const su2double* b, su2double* c);
510
511 /*!
512 * \brief Compute a portion of the c matrix one block at a time.
513 Handle ragged edges with calls to a slow but general function.
514 * \param[in] m - Number of rows of a and c.
515 * \param[in] n - Number of columns of b and c.
516 * \param[in] k - Number of columns of a and number of rows of b.
517 * \param[in] a - Input matrix in the multiplication.
518 * \param[in] lda - Leading dimension of the matrix a.
519 * \param[in] b - Input matrix in the multiplication.
520 * \param[in] ldb - Leading dimension of the matrix b.
521 * \param[out] c - Result of the matrix product a*b.
522 * \param[in] ldc - Leading dimension of the matrix c.
523 */
524 void gemm_inner(int m, int n, int k, const su2double* a, int lda, const su2double* b, int ldb, su2double* c, int ldc);
525
526 /*!
527 * \brief Naive gemm implementation to handle arbitrary sized matrices.
528 * \param[in] m - Number of rows of a and c.
529 * \param[in] n - Number of columns of b and c.
530 * \param[in] k - Number of columns of a and number of rows of b.
531 * \param[in] a - Input matrix in the multiplication.
532 * \param[in] lda - Leading dimension of the matrix a.
533 * \param[in] b - Input matrix in the multiplication.
534 * \param[in] ldb - Leading dimension of the matrix b.
535 * \param[out] c - Result of the matrix product a*b.
536 * \param[in] ldc - Leading dimension of the matrix c.
537 */
538 void gemm_arbitrary(int m, int n, int k, const su2double* a, int lda, const su2double* b, int ldb, su2double* c,
539 int ldc);
540#endif
541};
#define M(I, J)
#define A(I, J)
CNewtonIntegration::Scalar Scalar
Definition CNewtonIntegration.cpp:31
int main(int argc, char *argv[])
Definition SU2_CFD.cpp:37
#define C(i, j)
Definition blas_structure.cpp:133
#define B(i, j)
Definition blas_structure.cpp:132
Class, which serves as an interface to the BLAS functionalities needed.
Definition blas_structure.hpp:41
static void EigenDecomposition(const Mat &A_ij, Mat &Eig_Vec, Vec &Eig_Val, int n, W &e)
Decomposes the symmetric matrix A_ij, into eigenvectors and eigenvalues.
Definition blas_structure.hpp:439
CBlasStructure(void)
Constructor of the class. Initialize the constant member variables.
Definition blas_structure.cpp:53
static void EigenRecomposition(Mat &A_ij, const Mat &Eig_Vec, const Vec &Eig_Val, int n)
Recomposes the eigenvectors and eigenvalues into a matrix.
Definition blas_structure.hpp:458
void gemv(const int M, const int N, const su2double *A, const su2double *x, su2double *y)
Function, which carries out a dense matrix vector product y = A x. It is a limited version of the BLA...
Definition blas_structure.cpp:99
static void tdma(const Vec &lower, const Vec &main, Vec &upper, Vec &rhs)
Algorithm to solve a linear system with a tridiagonal matrix.
Definition blas_structure.hpp:476
static void tred2(Mat &V, Vec &d, W &e, int n)
tred2 Author:
Definition blas_structure.hpp:169
void gemm(const int M, const int N, const int K, const su2double *A, const su2double *B, su2double *C, const CConfig *config)
Function, which carries out a dense matrix product. It is a limited version of the BLAS gemm function...
Definition blas_structure.cpp:63
static void inverse(const int M, Mat &mat)
Invert a square matrix.
Definition blas_structure.hpp:91
static void tql2(Mat &V, Vec &d, W &e, int n)
tql2 Author:
Definition blas_structure.hpp:316
void axpy(const int n, const su2double a, const su2double *x, const int incx, su2double *y, const int incy)
Function, to carry out the axpy operation, i.e y += a*x.
Main class for defining the problem; basically this class reads the configuration file,...
Definition CConfig.hpp:64
passivedouble su2double
Definition code_config.hpp:181
FORCEINLINE ARRAY_T sqrt(const ARRAY_T &x)
Definition special_vectorization.hpp:116
FORCEINLINE ARRAY_T pow(const ARRAY_T &a, const ARRAY_T &b)
Definition special_vectorization.hpp:179
@ V
Menter k-w SST model with vorticity production terms.
@ W
W-cycle multigrid solver.