MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
maiamath.h
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7// Copyright (C) 2024 The m-AIA AUTHORS
8//
9// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
10//
11// SPDX-License-Identifier: LGPL-3.0-only
12
13// Copyright (C) 2024 The m-AIA AUTHORS
14//
15// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
16//
17// SPDX-License-Identifier: LGPL-3.0-only
18
19
20// Copyright (C) 2024 The m-AIA AUTHORS
21//
22// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
23//
24// SPDX-License-Identifier: LGPL-3.0-only
25
26
27// Copyright (C) 2024 The m-AIA AUTHORS
28//
29// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
30//
31// SPDX-License-Identifier: LGPL-3.0-only
32
33
34// Copyright (C) 2019 The m-AIA AUTHORS
35//
36// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
37//
38// SPDX-License-Identifier: LGPL-3.0-only
39
40
41#ifndef MATH_H_
42#define MATH_H_
43
44// TODO: Remove all `useEigenOld` stuff after switching to Eigen3.4.0
45//#define useEigenOld
46
47#include <algorithm>
48#include <array>
49#include <cassert>
50#include <cfloat>
51#include <cmath>
52#include <complex>
53#include <functional>
54#include <numeric>
55#include <type_traits>
56#include "COMM/mpioverride.h"
58#include "INCLUDE/maiatypes.h"
59#include "MEMORY/scratch.h"
60#include "debug.h"
61#include "tensor.h"
62namespace maia {
63namespace math {
64inline void quickSortImpl(MInt* a, MInt start, MInt end);
65inline void quickSort(MInt* a, MInt start, MInt end);
69
73template <MInt nDim, typename T, typename U>
74inline T* vecAdd(T* const result, const U* const a) {
75 std::transform(a, a + nDim, result, result, std::plus<T>());
76 return result;
77}
78template <MInt nDim, typename T, typename U, typename... Ts>
79inline T* vecAdd(T* const result, const U* const a, const Ts... b) {
80 std::transform(a, a + nDim, result, vecAdd<nDim>(result, b...), std::plus<T>());
81 return result;
82}
83
85template <MInt nDim, typename T, typename... Ts>
86inline void vecAvg(T* const M, const Ts* const... args) {
87 std::fill_n(M, nDim, 0.0);
88 maia::math::vecAdd<nDim>(M, args...);
89 constexpr std::size_t n = sizeof...(Ts);
90 std::transform(M, M + nDim, M, std::bind(std::multiplies<T>(), std::placeholders::_1, 1.0 / n));
91}
92
93
100template <typename T>
101inline void cross(const T* const u, const T* const v, T* const c) {
102 c[0] = u[1] * v[2] - v[1] * u[2];
103 c[1] = u[2] * v[0] - v[2] * u[0];
104 c[2] = u[0] * v[1] - v[0] * u[1];
105}
106
112template <typename T>
113inline std::array<T, 3> cross(const std::array<T, 3>& u, const std::array<T, 3>& v) {
114 std::array<T, 3> result;
115 cross(&u[0], &v[0], &result[0]);
116 return result;
117}
118// 2D case
119template <typename T>
120inline T cross(const std::array<T, 2>& u, const std::array<T, 2>& v) {
121 return u[0] * v[1] - u[1] * v[0];
122}
123
129template <typename T>
130inline T* cross(const T (&u)[3], const T (&v)[3]) {
131 T result[3]{};
132 cross(&u[0], &v[0], &result[0]);
133 return result;
134}
135// 2D case
136template <typename T>
137inline T cross(const T (&u)[2], const T (&v)[2]) {
138 return u[0] * v[1] - u[1] * v[0];
139}
140
147template <typename T, std::size_t N>
148inline MFloat norm(const std::array<T, N>& u) {
149 static_assert(N > 1, "ERROR: Invalid norm call!");
150
151 if(N == 2) {
152 return std::sqrt(u[0] * u[0] + u[1] * u[1]);
153 }
154 if(N == 3) {
155 return std::sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
156 }
157 return std::sqrt(std::accumulate(u.begin(), u.end(), 0.0, [](const MFloat& a, const T& b) { return a + b * b; }));
158}
159
166template <typename T>
167inline MFloat norm(const T* const u, const MInt N) {
168 ASSERT(N > 1, "ERROR: Invalid norm call!");
169
170 if(N == 2) {
171 return std::sqrt(u[0] * u[0] + u[1] * u[1]);
172 }
173 if(N == 3) {
174 return std::sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
175 }
176
177 MFloat tmp = 0;
178 for(MInt i = 0; i < N; i++) {
179 tmp += u[i] * u[i];
180 }
181
182 return std::sqrt(tmp);
183}
184
190template <typename T, std::size_t N>
191inline void normalize(std::array<T, N>& u) {
192 const MFloat inverse = 1.0 / norm(u);
193
194 if(N == 2) {
195 u[0] *= inverse;
196 u[1] *= inverse;
197 return;
198 }
199 if(N == 3) {
200 u[0] *= inverse;
201 u[1] *= inverse;
202 u[2] *= inverse;
203 return;
204 }
205
206 std::for_each(u.begin(), u.end(), [inverse](T& a) { a *= inverse; });
207}
208
214template <typename T>
215inline void normalize(T* const u, const MInt N) {
216 const MFloat inverse = 1.0 / norm(u, N);
217
218 if(N == 2) {
219 u[0] *= inverse;
220 u[1] *= inverse;
221 return;
222 }
223 if(N == 3) {
224 u[0] *= inverse;
225 u[1] *= inverse;
226 u[2] *= inverse;
227 return;
228 }
229
230 for(MInt i = 0; i < N; i++) {
231 u[i] *= inverse;
232 }
233}
234
241template <typename T, std::size_t N>
242inline std::array<T, N> normalized(const std::array<T, N>& u) {
243 std::array<T, N> n(u);
244 normalize(n);
245 return n;
246}
247
248template <MInt nDim>
249inline MFloat distance(const MFloat* a, const MFloat* b) {
250 IF_CONSTEXPR(nDim == 2) { return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1])); }
251 IF_CONSTEXPR(nDim == 3) { return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2])); }
252 return -NAN;
253}
254
255inline MFloat distance(const std::array<MFloat, 2> a, const std::array<MFloat, 2> b) {
256 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]));
257}
258
259inline MFloat distance(const std::array<MFloat, 3> a, const std::array<MFloat, 3> b) {
260 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2]));
261}
262
263inline MFloat distance(const MFloat* const a, const std::array<MFloat, 2> b) {
264 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]));
265}
266
267inline MFloat distance(const MFloat* const a, const std::array<MFloat, 3> b) {
268 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2]));
269}
270
271inline MFloat distance(const std::array<MFloat, 2> a, const MFloat* const b) {
272 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]));
273}
274
275inline MFloat distance(std::array<MFloat, 3> a, const MFloat* const b) {
276 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2]));
277}
278
280 // init
281 for(MInt i = 0; i < dim; i++) {
282 for(MInt j = 0; j < dim; j++) {
283 result(i, j) = 0.0;
284 }
285 }
286
287 // multiply
288 for(MInt i = 0; i < dim; i++) {
289 for(MInt j = 0; j < dim; j++) {
290 for(MInt k = 0; k < dim; k++) {
291 result(i, j) += m1(i, k) * m2(k, j);
292 }
293 }
294 }
295}
296
298 MInt m1_m, MInt m2_n, MInt m2_m) {
299 // m1 has the dimension n x m
300 // m2 has the dimension n x m
301 if(m1_m != m2_n) mTerm(1, AT_, "Dimension of matrix multiplication does not match!!!");
302 // init
303 for(MInt i = 0; i < m1_n; i++) {
304 for(MInt j = 0; j < m2_m; j++) {
305 result(i, j) = F0;
306 }
307 }
308
309 // multiply
310 for(MInt i = 0; i < m1_n; i++) {
311 for(MInt j = 0; j < m2_m; j++) {
312 for(MInt k = 0; k < m1_m; k++) {
313 result(i, j) += m1(i, k) * m2(k, j);
314 }
315 }
316 }
317}
318
320 MInt dim2) {
321 for(MInt i = 0; i < dim1; i++) {
322 for(MInt j = 0; j < dim2; j++) {
323 result(i, j) = m1(i, j) + m2(i, j);
324 }
325 }
326}
327
329 MFloat ret_val = 0.0;
330 for(MInt i = 0; i < dim1; i++) {
331 for(MInt j = 0; j < dim2; j++) {
332 ret_val += m(i, j) * m(i, j);
333 }
334 }
335
336 return ret_val;
337}
338
340 return sqrt(frobeniusMatrixNormSquared(m, dim1, dim2));
341}
342
344 // This subroutine calculates the First Kind Bessel Function of
345 // order 0, for any real number X. The polynomial approximation by
346 // series of Chebyshev polynomials is used for 0<X<8 and 0<8/X<1.
347 // REFERENCES:
348 // M.ABRAMOWITZ,I.A.STEGUN, HANDBOOK OF MATHEMATICAL FUNCTIONS, 1965.
349 // C.W.CLENSHAW, NATIONAL PHYSICAL LABORATORY MATHEMATICAL TABLES,
350 // VOL.5, 1962.
351
352 const MFloat p1 = 1.0, p2 = -0.1098628627e-2, p3 = 0.2734510407e-4, p4 = -0.2073370639e-5, p5 = 0.2093887211e-6,
353 q1 = -0.1562499995e-1, q2 = 0.1430488765e-3, q3 = -0.6911147651e-5, q4 = 0.7621095161e-6,
354 q5 = -0.9349451520e-7, r1 = 57568490574.0, r2 = -13362590354.0, r3 = 651619640.7, r4 = -11214424.18,
355 r5 = 77392.33017, r6 = -184.9052456, s1 = 57568490411.0, s2 = 1029532985.0, s3 = 9494680.718,
356 s4 = 59272.64853, s5 = 267.8532712, s6 = 1.0;
357 MFloat ax, fr, fs, z, fp, fq1, xx, y, tmp;
358
359 if(approx(x, 0.0, std::numeric_limits<MFloat>::epsilon())) {
360 return 1.0;
361 }
362
363 ax = fabs(x);
364 if(ax < 8.0) {
365 y = x * x;
366 fr = r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6))));
367 fs = s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))));
368 tmp = fr / fs;
369 } else {
370 z = 8. / ax;
371 y = z * z;
372 xx = ax - 0.785398164;
373 fp = p1 + y * (p2 + y * (p3 + y * (p4 + y * p5)));
374 fq1 = q1 + y * (q2 + y * (q3 + y * (q4 + y * q5)));
375 tmp = std::sqrt(0.636619772 / ax) * (fp * cos(xx) - z * fq1 * sin(xx));
376 }
377 return tmp;
378}
379
381 // This subroutine calculates the First Kind Bessel Function of
382 // order 1, for any real number X. The polynomial approximation by
383 // series of Chebyshev polynomials is used for 0<X<8 and 0<8/X<1.
384 // REFERENCES:
385 // M.ABRAMOWITZ,I.A.STEGUN, HANDBOOK OF MATHEMATICAL FUNCTIONS, 1965.
386 // C.W.CLENSHAW, NATIONAL PHYSICAL LABORATORY MATHEMATICAL TABLES,
387 // VOL.5, 1962.
388
389 const MFloat p1 = 1.0, p2 = 0.183105e-2, p3 = -0.3516396496e-4, p4 = 0.2457520174e-5, p5 = -0.240337019e-6,
390 p6 = 0.636619772, q1 = 0.04687499995, q2 = -0.2002690873e-3, q3 = 0.8449199096e-5, q4 = -0.88228987e-6,
391 q5 = 0.105787412e-6, r1 = 72362614232.0, r2 = -7895059235.0, r3 = 242396853.1, r4 = -2972611.439,
392 r5 = 15704.48260, r6 = -30.16036606, s1 = 144725228442.0, s2 = 2300535178.0, s3 = 18583304.74,
393 s4 = 99447.43394, s5 = 376.9991397, s6 = 1.0;
394
395 MFloat ax, fr, fs, y, z, fp, fq1, xx, tmp;
396
397 ax = fabs(x);
398 if(ax < 8.0) {
399 y = x * x;
400 fr = r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6))));
401 fs = s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))));
402 tmp = x * (fr / fs);
403 } else {
404 z = 8.0 / ax;
405 y = z * z;
406 xx = ax - 2.35619491;
407 fp = p1 + y * (p2 + y * (p3 + y * (p4 + y * p5)));
408 fq1 = q1 + y * (q2 + y * (q3 + y * (q4 + y * q5)));
409 tmp = sqrt(p6 / ax) * (cos(xx) * fp - z * sin(xx) * fq1) * (x < 0.0 ? -fabs(s6) : fabs(s6));
410 }
411 return tmp;
412}
413
414// bessel functions of first kind
415inline MFloat besselJi(MInt order, MFloat x) {
416 if(order == 0) {
417 return besselJ0(x);
418 }
419 if(order == 1) {
420 return besselJ1(x);
421 }
422 mTerm(1, AT_, "invalid order");
423}
424
425// cosinus using a lookuptable
426inline MFloat lincos(MFloat arg) {
427 MFloat SIGN = F1;
428 // lookuptable has 91 entries from 0 to pi/2
429 const MFloat darg = PIB2 / 90;
430
431 arg = std::fmod(std::abs(arg), F2 * PI);
432
433 if(arg > PI) {
434 SIGN *= -F1;
435 arg -= PI;
436 }
437
438 if(arg > PIB2) {
439 SIGN *= -F1;
440 arg = PI - arg;
441 }
442
443 const auto lowerInd = static_cast<MInt>(arg / darg);
444 const MFloat lowerVal = FTRIG[lowerInd];
445 const MFloat higherVal = FTRIG[lowerInd + 1];
446 const MFloat deltaArg = arg - lowerInd * darg;
447 const MFloat fac = deltaArg / darg;
448
449 return (lowerVal * (F1 - fac) + higherVal * fac) * SIGN;
450}
451
460inline void sortEigenVectors(MFloat A[3][3], MFloat w[3]) {
461 const MInt dim = 3;
462 MInt k;
463 for(MInt i = 0; i < (dim - 1); ++i) {
464 MFloat p = w[k = i];
465 for(MInt j = i; j < dim; ++j) {
466 if(w[j] >= p) {
467 p = w[k = j];
468 }
469 }
470 if(k != i) {
471 w[k] = w[i];
472 w[i] = p;
473 for(MInt j = 0; j < dim; ++j) {
474 p = A[j][i];
475 A[j][i] = A[j][k];
476 A[j][k] = p;
477 }
478 }
479 }
480}
481
482inline void quatMult(const MFloat* const qA, const MFloat* const qB, MFloat* const qC) {
483 MFloat crossProduct[3]{};
484 cross(qA, qB, &crossProduct[0]);
485
486 const MFloat dot = std::inner_product(qA, &qA[3], qB, 0.0);
487
488 for(MInt n = 0; n < 3; n++) {
489 qC[n] = qA[3] * qB[n] + qB[3] * qA[n] + crossProduct[n];
490 }
491 qC[3] = qA[3] * qB[3] - dot;
492}
493
494template <typename T>
495inline MInt sgn(T val) {
496 return (T(0) < val) - (val < T(0));
497}
498
506inline MFloat crankAngle(const MFloat time, const MFloat Strouhal, const MFloat offset, const MInt mode) {
507 const MFloat mu2 = Strouhal * F2 * PI;
508 MFloat cad = mu2 * time;
509
510 if(mode == 0) {
511 const MInt maxNoCycles = 20;
512 for(MInt cycle = maxNoCycles; cycle > 0; cycle--) {
513 if(cad >= 4 * PI * cycle) {
514 cad = cad - 4 * PI * cycle;
515 }
516 }
517 cad = cad * 180 / PI;
518
519 cad = cad + offset;
520
521 } else {
522 ASSERT(mode == 1, "Incorrect mode!");
523 cad = cad + offset * PI / 180;
524 }
525
526 return cad;
527}
528
534 R(0, 0) = q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3];
535 R(1, 1) = q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3];
536 R(2, 2) = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
537
538 R(0, 1) = F2 * (q[1] * q[2] + q[0] * q[3]);
539 R(0, 2) = F2 * (q[1] * q[3] - q[0] * q[2]);
540 R(1, 0) = F2 * (q[1] * q[2] - q[0] * q[3]);
541 R(1, 2) = F2 * (q[2] * q[3] + q[0] * q[1]);
542 R(2, 0) = F2 * (q[1] * q[3] + q[0] * q[2]);
543 R(2, 1) = F2 * (q[2] * q[3] - q[0] * q[1]);
544}
545
550inline void rotation2quaternion(MFloat* rotation, MFloat* quaternion) {
551 quaternion[0] = cos(F1B2 * rotation[1]) * cos(F1B2 * (rotation[2] + rotation[0]));
552 quaternion[1] = sin(F1B2 * rotation[1]) * sin(F1B2 * (rotation[2] - rotation[0]));
553 quaternion[2] = sin(F1B2 * rotation[1]) * cos(F1B2 * (rotation[2] - rotation[0]));
554 quaternion[3] = cos(F1B2 * rotation[1]) * sin(F1B2 * (rotation[2] + rotation[0]));
555}
556
562 for(MInt i = 0; i < A.size0(); i++) {
563 c[i] = F0;
564 for(MInt j = 0; j < A.size1(); j++) {
565 c[i] += A(i, j) * b[j];
566 }
567 }
568}
569
575 for(MInt i = 0; i < A.size1(); i++) {
576 c[i] = F0;
577 for(MInt j = 0; j < A.size0(); j++) {
578 c[i] += A(j, i) * b[j];
579 }
580 }
581}
582
583
584// -----------------------------------------------------------------------------------------------------------
585
586
587inline MInt inverse(MFloat** a, MFloat** ainv, MInt n, const MFloat epsilon) {
588 MInt s;
589 MInt pRow = 0; // pivot row
590 MBool error = false;
591 MFloat f;
592 MFloat maximum;
593 MInt pivot = 1;
594
595 // add the unity matrix
596 for(MInt i = 0; i < n; i++) {
597 for(MInt j = 0; j < n; j++) {
598 a[i][n + j] = F0;
599 if(i == j) {
600 a[i][n + j] = F1;
601 }
602 }
603 }
604
605 // Gauss algorithm
606 error = false;
607 s = 0;
608 while(s < n) {
609 maximum = fabs(a[s][s]);
610 if(pivot) {
611 pRow = s;
612 for(MInt i = s + 1; i < n; i++) {
613 if(fabs(a[i][s]) > maximum) {
614 maximum = fabs(a[i][s]);
615 pRow = i;
616 }
617 }
618 }
619 if(maximum < epsilon) {
620 error = true;
621 }
622
623 if(error) {
624 std::cerr << "Error in matrix inverse computation " << s << " " << a[s][s] << std::endl;
625 for(MInt i = 0; i < n; i++) {
626 for(MInt j = 0; j < n; j++) {
627 std::cerr << a[i][j] << " ";
628 }
629 std::cerr << std::endl;
630 }
631 // mTerm(1, AT_, "Error in matrix inverse computation ");
632 std::cerr << "Error in matrix inverse computation " << std::endl;
633 return 0;
634 }
635
636 if(pivot) {
637 if(pRow != s) // exchange rows if required
638 {
639 MFloat h;
640 for(MInt j = s; j < 2 * n; j++) {
641 h = a[s][j];
642 a[s][j] = a[pRow][j];
643 a[pRow][j] = h;
644 }
645 }
646 }
647
648 f = a[s][s];
649 for(MInt j = s; j < 2 * n; j++) {
650 a[s][j] = a[s][j] / f;
651 }
652
653 // elimination
654 for(MInt i = 0; i < n; i++) {
655 if(i != s) {
656 f = -a[i][s];
657 for(MInt j = s; j < 2 * n; j++) {
658 a[i][j] += f * a[s][j];
659 }
660 }
661 }
662 s++;
663 }
664
665 if(error) {
666 std::cerr << "Error 2 in inverse matrix computation" << std::endl;
667 // mTerm(1,AT_,"Error 2 in inverse matrix computation");
668 return 0;
669 }
670
671 // copy
672 for(MInt i = 0; i < n; i++) {
673 for(MInt j = 0; j < n; j++) {
674 ainv[i][j] = a[i][n + j];
675 }
676 }
677
678 return 1;
679}
680
681inline MInt quickSortPartition(MInt* a, MInt start, MInt end) {
682 MInt i, temp;
683 //---
684
685 i = start - 1;
686
687 for(MInt j = start; j < end; j++) {
688 if(a[j] <= a[end]) {
689 i++;
690 // swap elements i and j
691 temp = a[i];
692 a[i] = a[j];
693 a[j] = temp;
694 }
695 }
696 // swap the pivot
697 temp = a[i + 1];
698 a[i + 1] = a[end];
699 a[end] = temp;
700
701 return i + 1;
702}
703
704inline void quickSortImpl(MInt* a, MInt start, MInt end) {
705 MInt pivot;
706
707 if(start >= end) {
708 return;
709 }
710
711 pivot = maia::math::quickSortPartition(a, start, end);
712 maia::math::quickSort(a, start, pivot - 1);
713 maia::math::quickSort(a, pivot + 1, end);
714}
715
716inline void quickSort(MInt* a, MInt start, MInt end) { maia::math::quickSortImpl(a, start, end); }
717
718
719// removes double entries in arrays
720// retains the sorting
721// returns the new size of the array
723 for(MInt i = 1; i < size; i++) {
724 // find double entry
725 if(a[i] != a[i - 1]) {
726 continue;
727 }
728
729 // shift entries forward
730 for(MInt k = i; k < size - 1; k++) {
731 a[k] = a[k + 1];
732 }
733 size--;
734 i--;
735 }
736
737 return size;
738}
739
754inline void calculateLegendrePolyAndDeriv(MInt Nmax, MFloat x, MFloat* polynomial, MFloat* derivative) {
755 // TRACE();
756
757 // Create temporary storage for the polynomial and its derivative
758 MFloat poly = F0;
759 MFloat deriv = F0;
760
761 // Explicitly calculate the first two values of the three term recursion
762 if(Nmax == 0) {
763 poly = F1;
764 deriv = F0;
765 } else if(Nmax == 1) {
766 poly = x;
767 deriv = F1;
768 } else {
769 MFloat polyLast1, polyLast2, derivLast1, derivLast2;
770
771 polyLast2 = F1;
772 polyLast1 = x;
773 derivLast2 = F0;
774 derivLast1 = F1;
775
776 // Calculate the polynomial and its derivative for higher degrees
777 // (Nmax >= 2)
778 for(MInt k = 2; k <= Nmax; k++) {
779 poly = (F2 * k - F1) / k * x * polyLast1 - (k - F1) / k * polyLast2;
780 deriv = derivLast2 + (F2 * k - F1) * polyLast1;
781 polyLast2 = polyLast1;
782 polyLast1 = poly;
783 derivLast2 = derivLast1;
784 derivLast1 = deriv;
785 }
786 }
787
788 // Save results to pointer locations
789 *polynomial = poly;
790 *derivative = deriv;
791}
792
806inline void calculateLegendreGaussNodesAndWeights(MInt Nmax, MFloat* nodes, MFloat* wInt) {
807 TRACE();
808
809 // Reset nodes and weights
810 const MInt noNodes = Nmax + 1;
811 std::fill_n(&nodes[0], noNodes, F0);
812 std::fill_n(&wInt[0], noNodes, F0);
813
814 // Set tolerance and number of iterations. According to Kopriva09,
815 // 1.0E-15 and 10 should be more than sufficient.
816 const MFloat tol = F4 * MFloatEps;
817 const MInt noIterations = 10;
818
819 // Catch simple cases before going into the full loop
820 if(Nmax == 0) {
821 nodes[0] = F0;
822 wInt[0] = F2;
823 } else if(Nmax == 1) {
824 nodes[0] = -sqrt(F1B3);
825 wInt[0] = 1;
826 nodes[1] = -nodes[0];
827 wInt[1] = wInt[0];
828 } else {
829 // Use symmetry property of the roots of the Legendre polynomials
830 for(MInt j = 0; j < (Nmax + 1) / 2; j++) {
831 // Calculate starting guess for Newton method
832 nodes[j] = -cos((F2 * j + F1) / (F2 * Nmax + F2) * PI);
833
834 // Use Newton method to find root of Legendre polynomial
835 // -> this is also the integration node
836 MFloat poly, deriv;
837 for(MInt k = 0; k < noIterations; k++) {
838 calculateLegendrePolyAndDeriv(Nmax + 1, nodes[j], &poly, &deriv);
839 MFloat delta = -poly / deriv;
840 nodes[j] += delta;
841
842 // Stop iterations if error is small enough
843 if(fabs(delta) <= tol * fabs(nodes[j])) {
844 break;
845 }
846 }
847
848 // Calculate weight
849 calculateLegendrePolyAndDeriv(Nmax + 1, nodes[j], &poly, &deriv);
850 wInt[j] = F2 / ((1 - nodes[j] * nodes[j]) * deriv * deriv);
851
852 // Set nodes and weights according to symmetry properties
853 nodes[Nmax - j] = -nodes[j];
854 wInt[Nmax - j] = wInt[j];
855 }
856 }
857
858 // If odd number of nodes (noNodes = Nmax + 1), set center node to
859 // origin (0.0) and calculate weight
860 if(Nmax % 2 == 0) {
861 MFloat poly, deriv;
862 calculateLegendrePolyAndDeriv(Nmax + 1, F0, &poly, &deriv);
863 nodes[Nmax / 2] = F0;
864 wInt[Nmax / 2] = F2 / (deriv * deriv);
865 }
866}
873inline MFloat RBF(const MFloat R, const MFloat R0) { return (F1 / sqrt(F1 + POW2(R / R0))); }
874
875
876// ---------------------------------------------------------------------------
877
878
883#define MAIA_TRANSITION_FUNCTION 2
884
885inline MFloat deltaFun(const MFloat r, const MFloat r0, const MFloat r1) {
886 MFloat R = mMin(F1, mMax(F0, ((r - r0) / (r1 - r0))));
887#if MAIA_TRANSITION_FUNCTION == 0
888 return (r < r1) ? F0 : F1;
889#elif MAIA_TRANSITION_FUNCTION == 1
890 return R;
891#elif MAIA_TRANSITION_FUNCTION == 2
892 return POW2(R) * (3.0 - 2.0 * R);
893#elif MAIA_TRANSITION_FUNCTION == 3
894 return POW3(R) * (10.0 + R * (6.0 * R - 15.0)); // may cause stability issues
895#elif MAIA_TRANSITION_FUNCTION == 4
896 return POW3(R) * (6.0 + R * (2.0 * R - 7.0)); // approximates 0.5*(1.0-cos(PI*pow(R,1.25)));
897#elif MAIA_TRANSITION_FUNCTION == 5
898 return F1B2 * (F1 + sin(PI * (F3B2 + R)));
899#endif
900}
901
902// MATLAB linspace
903inline std::vector<MFloat> linSpace(const MFloat start, const MFloat end, const MInt num) {
904 std::vector<MFloat> linspaced(num);
905 MFloat delta = (end - start) / (MFloat(num) - F1);
906 for(auto i = 0; i < num; i++) {
907 linspaced[i] = start + delta * i;
908 }
909 return linspaced;
910}
911
912inline MFloat getSector(MFloat y, MFloat z, MFloat azimuthalAngle) {
913 MFloat angle = atan(z / y);
914 if(y < 0) {
915 if(z >= 0) {
916 angle += PI;
917 } else {
918 angle -= PI;
919 }
920 }
921 angle += PI;
922 return (angle - std::fmod(angle, azimuthalAngle / 180.0 * PI)) / (azimuthalAngle / 180.0 * PI);
923}
924
926 MFloat angle = atan(z / y);
927 if(y < 0) {
928 if(z >= 0) {
929 angle += PI;
930 } else {
931 angle -= PI;
932 }
933 }
934 return angle;
935}
936
937//------------------------------------------------------------------------
938
939template <typename T, std::size_t N>
940MFloat determinant(std::array<T, N>& m);
941template <typename T, std::size_t N>
942MFloat determinant(std::array<std::array<T, N>, N>& m);
943void invert(MFloat* A, const MInt m, const MInt n);
944template <class T>
945void invert(T& A, T& AInv, const MInt m, const MInt n);
946template <class T>
947void invert(T& A, T& weights, T& AInv, const MInt m, const MInt n);
948template <class T>
949MInt invertR(T& A, T& weights, T& AInv, const MInt m, const MInt n);
950void solveDenseMatrix(MFloat* A_coeff, MInt** pos, const MInt n, const MInt m, MFloat* b, MFloat* x);
951void solveSparseMatrixIterative(MFloat* A_coeff, MInt** pos, const MInt n, const MInt m, MFloat* b, MFloat* x);
952void solveSparseMatrix(MFloat* A_coeff, MInt** pos, const MInt n, const MInt m, MFloat* b, MFloat* x);
953void multiplySparseMatrixVector(MFloat* A_coeff, MInt** pos, const MInt n, const MInt m, MFloat* b_in, MFloat* x_final);
954void calcEigenValues(MFloat A[3][3], MFloat w[3]);
955void calcEigenValues(MFloat** A_in, MFloat* lambda_in, const MInt m);
956void calcEigenVectors(MFloat A[3][3], MFloat Q[3][3], MFloat w[3]);
957template <MInt nDim>
958void solveQR(std::array<std::array<MFloat, nDim>, nDim>& A_, std::array<MFloat, nDim>& b_);
959template <typename T, std::size_t N>
960void adjointRow(std::array<std::array<T, N>, N>& m, std::array<T, N>& A, const MInt r);
961template <typename T>
962void adjoint1stRow4x4(std::array<std::array<T, 4>, 4>& m, std::array<T, 4>& A);
963template <typename T, std::size_t N>
964void adjoint1stRow(std::array<std::array<T, N>, N>& m, std::array<T, N>& A);
965std::vector<MFloat> svd(MFloat* const A, MFloat* const b, const MInt m, const MInt n, MFloat* const x);
966} // namespace math
967} // namespace maia
968#endif // MATH_H_
This class is a ScratchSpace.
Definition: scratch.h:758
MInt size1() const
Definition: scratch.h:299
MInt size0() const
Definition: scratch.h:298
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
MFloat frobeniusMatrixNorm(MFloatScratchSpace &m, MInt dim1, MInt dim2)
Definition: maiamath.h:339
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101
void adjoint1stRow(std::array< std::array< T, N >, N > &m, std::array< T, N > &A)
Definition: maiamath.cpp:114
MFloat RBF(const MFloat R, const MFloat R0)
radial base function
Definition: maiamath.h:873
std::vector< MFloat > svd(MFloat *const A, MFloat *const b, const MInt m, const MInt n, MFloat *const x)
Definition: maiamath.cpp:514
void quickSortImpl(MInt *a, MInt start, MInt end)
Definition: maiamath.h:704
MFloat determinant(std::array< T, N > &m)
Definition: maiamath.cpp:130
void multiplySparseMatrixVector(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:431
void rotation2quaternion(MFloat *rotation, MFloat *quaternion)
Definition: maiamath.h:550
MInt sgn(T val)
Definition: maiamath.h:495
T * vecAdd(T *const result, const U *const a)
Linear Algebra.
Definition: maiamath.h:74
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249
void adjoint1stRow4x4(std::array< std::array< T, 4 >, 4 > &m, std::array< T, 4 > &A)
Definition: maiamath.cpp:97
void calculateLegendrePolyAndDeriv(MInt Nmax, MFloat x, MFloat *polynomial, MFloat *derivative)
Evaluates the Legendre polynomial and its derivative of degree Nmax at point x.
Definition: maiamath.h:754
std::vector< MFloat > linSpace(const MFloat start, const MFloat end, const MInt num)
Definition: maiamath.h:903
void matrixVectorProduct(MFloat *c, MFloatScratchSpace &A, MFloat *b)
c=A*b
Definition: maiamath.h:561
void sortEigenVectors(MFloat A[3][3], MFloat w[3])
Sorts the eigenvalues and the associated eigenvectors from large to small.
Definition: maiamath.h:460
MFloat besselJ0(MFloat x)
Definition: maiamath.h:343
MInt removeDoubleEntries(MInt *a, MInt size)
Definition: maiamath.h:722
void invert(MFloat *A, const MInt m, const MInt n)
Definition: maiamath.cpp:171
MFloat besselJ1(MFloat x)
Definition: maiamath.h:380
void solveQR(std::array< std::array< MFloat, nDim >, nDim > &A_, std::array< MFloat, nDim > &b_)
Definition: maiamath.cpp:449
void normalize(std::array< T, N > &u)
Definition: maiamath.h:191
MFloat frobeniusMatrixNormSquared(MFloatScratchSpace &m, MInt dim1, MInt dim2)
Definition: maiamath.h:328
MFloat besselJi(MInt order, MFloat x)
Definition: maiamath.h:415
void computeRotationMatrix(MFloatScratchSpace &R, MFloat *q)
rotation matrix co-rotating(~inertial) frame -> body-fixed frame
Definition: maiamath.h:533
MFloat deltaFun(const MFloat r, const MFloat r0, const MFloat r1)
Definition: maiamath.h:885
void calcEigenVectors(MFloat A[3][3], MFloat Q[3][3], MFloat w[3])
Definition: maiamath.cpp:503
void calculateLegendreGaussNodesAndWeights(MInt Nmax, MFloat *nodes, MFloat *wInt)
Calculate the Gauss integration nodes and weight for the Legendre polynomials on the interval [-1,...
Definition: maiamath.h:806
MFloat getSector(MFloat y, MFloat z, MFloat azimuthalAngle)
Definition: maiamath.h:912
void solveSparseMatrix(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:315
MFloat crankAngle(const MFloat time, const MFloat Strouhal, const MFloat offset, const MInt mode)
help-function for engine calculations which returns the crank-angle for a given time,...
Definition: maiamath.h:506
void solveSparseMatrixIterative(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:357
void quickSort(MInt *a, MInt start, MInt end)
Definition: maiamath.h:716
MFloat getAngle(MFloat y, MFloat z)
Definition: maiamath.h:925
MFloat norm(const std::array< T, N > &u)
Definition: maiamath.h:148
std::array< T, N > normalized(const std::array< T, N > &u)
Definition: maiamath.h:242
MFloat lincos(MFloat arg)
Definition: maiamath.h:426
void addMatrices(MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt dim1, MInt dim2)
Definition: maiamath.h:319
MInt inverse(MFloat **a, MFloat **ainv, MInt n, const MFloat epsilon)
Definition: maiamath.h:587
void multiplyMatricesSq(MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt dim)
Definition: maiamath.h:279
void multiplyMatrices(MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt m1_n, MInt m1_m, MInt m2_n, MInt m2_m)
Definition: maiamath.h:297
void vecAvg(T *const M, const Ts *const ... args)
Computes the arithmetic mean of an arbritary number of vectors of dimension nDim and returns it in M.
Definition: maiamath.h:86
void calcEigenValues(MFloat A[3][3], MFloat w[3])
Definition: maiamath.cpp:475
void adjointRow(std::array< std::array< T, N >, N > &m, std::array< T, N > &A, const MInt r)
Definition: maiamath.cpp:82
MInt quickSortPartition(MInt *a, MInt start, MInt end)
Definition: maiamath.h:681
void quatMult(const MFloat *const qA, const MFloat *const qB, MFloat *const qC)
Definition: maiamath.h:482
void solveDenseMatrix(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:400
MInt invertR(T &A, T &weights, T &AInv, const MInt m, const MInt n)
Definition: maiamath.cpp:280
void matrixVectorProductTranspose(MFloat *c, MFloatScratchSpace &A, MFloat *b)
c=A^t*b
Definition: maiamath.h:574
Namespace for auxiliary functions/classes.
Definition: contexttypes.h:19
define array structures