EigenMatrix.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Code created 2014-2018 by Alberto Passalacqua
9 Contributed 2018-07-31 to the OpenFOAM Foundation
10 Copyright (C) 2018 OpenFOAM Foundation
11 Copyright (C) 2019-2020 Alberto Passalacqua
12 Copyright (C) 2020 OpenCFD Ltd.
13-------------------------------------------------------------------------------
14License
15 This file is part of OpenFOAM.
16
17 OpenFOAM is free software: you can redistribute it and/or modify it
18 under the terms of the GNU General Public License as published by
19 the Free Software Foundation, either version 3 of the License, or
20 (at your option) any later version.
21
22 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
23 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
29
30\*---------------------------------------------------------------------------*/
31
32#include "EigenMatrix.H"
33
34// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35
36template<class cmptType>
38{
39 for (label j = 0; j < n_; ++j)
40 {
41 EValsRe_[j] = EVecs_[n_ - 1][j];
42 }
43
44 // Householder reduction to tridiagonal form
45 for (label i = n_ - 1; i > 0; --i)
46 {
47 // Scale to avoid under/overflow.
48 cmptType scale = Zero;
49 cmptType h = Zero;
50
51 for (label k = 0; k < i; ++k)
52 {
53 scale = scale + mag(EValsRe_[k]);
54 }
55
56 if (scale == 0.0)
57 {
58 EValsIm_[i] = EValsRe_[i - 1];
59
60 for (label j = 0; j < i; ++j)
61 {
62 EValsRe_[j] = EVecs_[i - 1][j];
63 EVecs_[i][j] = Zero;
64 EVecs_[j][i] = Zero;
65 }
66 }
67 else
68 {
69 // Generate Householder vector
70 for (label k = 0; k < i; ++k)
71 {
72 EValsRe_[k] /= scale;
73 h += EValsRe_[k]*EValsRe_[k];
74 }
75
76 cmptType f = EValsRe_[i - 1];
77 cmptType g = Foam::sqrt(h);
78
79 if (f > 0)
80 {
81 g = -g;
82 }
83
84 EValsIm_[i] = scale*g;
85 h -= f*g;
86 EValsRe_[i - 1] = f - g;
87
88 for (label j = 0; j < i; ++j)
89 {
90 EValsIm_[j] = Zero;
91 }
92
93 // Apply similarity transformation to remaining columns
94 for (label j = 0; j < i; ++j)
95 {
96 f = EValsRe_[j];
97 EVecs_[j][i] = f;
98 g = EValsIm_[j] + EVecs_[j][j]*f;
99
100 for (label k = j + 1; k <= i - 1; ++k)
101 {
102 g += EVecs_[k][j]*EValsRe_[k];
103 EValsIm_[k] += EVecs_[k][j]*f;
104 }
105
106 EValsIm_[j] = g;
107 }
108
109 f = Zero;
110
111 for (label j = 0; j < i; ++j)
112 {
113 EValsIm_[j] /= h;
114 f += EValsIm_[j]*EValsRe_[j];
115 }
116
117 cmptType hh = f/(2.0*h);
118
119 for (label j = 0; j < i; ++j)
120 {
121 EValsIm_[j] -= hh*EValsRe_[j];
122 }
123
124 for (label j = 0; j < i; ++j)
125 {
126 f = EValsRe_[j];
127 g = EValsIm_[j];
128
129 for (label k = j; k <= i - 1; ++k)
130 {
131 EVecs_[k][j] -=
132 (f*EValsIm_[k] + g*EValsRe_[k]);
133 }
134
135 EValsRe_[j] = EVecs_[i - 1][j];
136 EVecs_[i][j] = Zero;
137 }
138 }
139
140 EValsRe_[i] = h;
141 }
142
143 // Accumulate transformations
144 for (label i = 0; i < n_ - 1; ++i)
145 {
146 EVecs_[n_ - 1][i] = EVecs_[i][i];
147 EVecs_[i][i] = cmptType(1);
148 cmptType h = EValsRe_[i + 1];
149
150 if (h != 0.0)
151 {
152 for (label k = 0; k <= i; ++k)
153 {
154 EValsRe_[k] = EVecs_[k][i + 1]/h;
155 }
156
157 for (label j = 0; j <= i; ++j)
158 {
159 cmptType g = Zero;
160
161 for (label k = 0; k <= i; ++k)
162 {
163 g += EVecs_[k][i + 1]*EVecs_[k][j];
164 }
165
166 for (label k = 0; k <= i; ++k)
167 {
168 EVecs_[k][j] -= g*EValsRe_[k];
169 }
170 }
171 }
172
173 for (label k = 0; k <= i; ++k)
174 {
175 EVecs_[k][i + 1] = Zero;
176 }
177 }
178
179 for (label j = 0; j < n_; ++j)
180 {
181 EValsRe_[j] = EVecs_[n_ - 1][j];
182 EVecs_[n_ - 1][j] = Zero;
183 }
184
185 EVecs_[n_ - 1][n_ - 1] = cmptType(1);
186 EValsIm_[0] = Zero;
187}
188
189
190template<class cmptType>
192{
193 for (label i = 1; i < n_; ++i)
194 {
195 EValsIm_[i - 1] = EValsIm_[i];
196 }
197
198 EValsIm_[n_-1] = Zero;
199
200 cmptType f = Zero;
201 cmptType tst1 = Zero;
202 cmptType eps = pow(2.0, -52.0);
203
204 for (label l = 0; l < n_; l++)
205 {
206 // Find SMALL subdiagonal element
207 tst1 = max(tst1, mag(EValsRe_[l]) + mag(EValsIm_[l]));
208 label m = l;
209
210 // Original while-loop from Java code
211 while (m < n_)
212 {
213 if (mag(EValsIm_[m]) <= eps*tst1)
214 {
215 break;
216 }
217
218 ++m;
219 }
220
221 // If m == l, EValsRe_[l] is an eigenvalue, otherwise, iterate
222 if (m > l)
223 {
224 label iter = 0;
225
226 do
227 {
228 iter += 1;
229
230 // Compute implicit shift
231 cmptType g = EValsRe_[l];
232 cmptType p = (EValsRe_[l + 1] - g)/(2.0*EValsIm_[l]);
233 cmptType r = Foam::hypot(p, cmptType(1));
234
235 if (p < 0)
236 {
237 r = -r;
238 }
239
240 EValsRe_[l] = EValsIm_[l]/(p + r);
241 EValsRe_[l + 1] = EValsIm_[l]*(p + r);
242 cmptType dl1 = EValsRe_[l + 1];
243 cmptType h = g - EValsRe_[l];
244
245 for (label i = l + 2; i < n_; ++i)
246 {
247 EValsRe_[i] -= h;
248 }
249
250 f += h;
251
252 // Implicit QL transformation.
253 p = EValsRe_[m];
254 cmptType c = cmptType(1);
255 cmptType c2 = c;
256 cmptType c3 = c;
257 cmptType el1 = EValsIm_[l + 1];
258 cmptType s = Zero;
259 cmptType s2 = Zero;
260
261 for (label i = m - 1; i >= l; --i)
262 {
263 c3 = c2;
264 c2 = c;
265 s2 = s;
266 g = c*EValsIm_[i];
267 h = c*p;
268 r = std::hypot(p, EValsIm_[i]);
269 EValsIm_[i + 1] = s*r;
270 s = EValsIm_[i]/r;
271 c = p/r;
272 p = c*EValsRe_[i] - s*g;
273 EValsRe_[i + 1] = h + s*(c*g + s*EValsRe_[i]);
274
275 // Accumulate transformation
276 for (label k = 0; k < n_; ++k)
277 {
278 h = EVecs_[k][i + 1];
279 EVecs_[k][i + 1] = s*EVecs_[k][i] + c*h;
280 EVecs_[k][i] = c*EVecs_[k][i] - s*h;
281 }
282 }
283
284 p = -s*s2*c3*el1*EValsIm_[l]/dl1;
285 EValsIm_[l] = s*p;
286 EValsRe_[l] = c*p;
287 }
288 while (mag(EValsIm_[l]) > eps*tst1); // Convergence check
289 }
290
291 EValsRe_[l] = EValsRe_[l] + f;
292 EValsIm_[l] = Zero;
293 }
294
295 // Sorting eigenvalues and corresponding vectors
296 for (label i = 0; i < n_ - 1; ++i)
297 {
298 label k = i;
299 cmptType p = EValsRe_[i];
300
301 for (label j = i + 1; j < n_; ++j)
302 {
303 if (EValsRe_[j] < p)
304 {
305 k = j;
306 p = EValsRe_[j];
307 }
308 }
309
310 if (k != i)
311 {
312 EValsRe_[k] = EValsRe_[i];
313 EValsRe_[i] = p;
314
315 for (label j = 0; j < n_; ++j)
316 {
317 p = EVecs_[j][i];
318 EVecs_[j][i] = EVecs_[j][k];
319 EVecs_[j][k] = p;
320 }
321 }
322 }
323}
324
325
326template<class cmptType>
328{
329 DiagonalMatrix<cmptType> orth_(n_);
330
331 label low = 0;
332 label high = n_ - 1;
333
334 for (label m = low + 1; m <= high - 1; ++m)
335 {
336 // Scale column
337 cmptType scale = Zero;
338
339 for (label i = m; i <= high; ++i)
340 {
341 scale = scale + mag(H_[i][m - 1]);
342 }
343
344 if (scale != 0.0)
345 {
346 // Compute Householder transformation
347 cmptType h = Zero;
348
349 for (label i = high; i >= m; --i)
350 {
351 orth_[i] = H_[i][m - 1]/scale;
352 h += orth_[i]*orth_[i];
353 }
354
355 cmptType g = Foam::sqrt(h);
356
357 if (orth_[m] > 0)
358 {
359 g = -g;
360 }
361
362 h -= orth_[m]*g;
363 orth_[m] -= g;
364
365 // Apply Householder similarity transformation
366 // H = (I - u*u'/h)*H*(I - u*u')/h)
367 for (label j = m; j < n_; ++j)
368 {
369 cmptType f = Zero;
370
371 for (label i = high; i >= m; --i)
372 {
373 f += orth_[i]*H_[i][j];
374 }
375
376 f /= h;
377
378 for (label i = m; i <= high; ++i)
379 {
380 H_[i][j] -= f*orth_[i];
381 }
382 }
383
384 for (label i = 0; i <= high; ++i)
385 {
386 cmptType f = Zero;
387
388 for (label j = high; j >= m; --j)
389 {
390 f += orth_[j]*H_[i][j];
391 }
392
393 f /= h;
394
395 for (label j = m; j <= high; ++j)
396 {
397 H_[i][j] -= f*orth_[j];
398 }
399 }
400
401 orth_[m] = scale*orth_[m];
402 H_[m][m-1] = scale*g;
403 }
404 }
405
406 // Accumulate transformations
407 for (label i = 0; i < n_; ++i)
408 {
409 for (label j = 0; j < n_; ++j)
410 {
411 EVecs_[i][j] = (i == j ? 1.0 : 0.0);
412 }
413 }
414
415 for (label m = high - 1; m >= low + 1; --m)
416 {
417 if (H_[m][m - 1] != 0.0)
418 {
419 for (label i = m + 1; i <= high; ++i)
420 {
421 orth_[i] = H_[i][m - 1];
422 }
423
424 for (label j = m; j <= high; ++j)
425 {
426 cmptType g = Zero;
427
428 for (label i = m; i <= high; ++i)
429 {
430 g += orth_[i]*EVecs_[i][j];
431 }
432
433 // Double division avoids possible underflow
434 g = (g/orth_[m])/H_[m][m - 1];
435
436 for (label i = m; i <= high; ++i)
437 {
438 EVecs_[i][j] += g*orth_[i];
439 }
440 }
441 }
442 }
443}
444
445
446template<class cmptType>
448{
449 // Initialize
450 label nn = n_;
451 label n = nn - 1;
452 label low = 0;
453 label high = nn - 1;
454 cmptType eps = pow(2.0, -52.0);
455 cmptType exshift = Zero;
456 cmptType p = 0, q = 0, r = 0, s = 0, z = 0, t, w, x, y;
457
458 // Store roots isolated by balance and compute matrix norm
459 cmptType norm = Zero;
460
461 for (label i = 0; i < nn; ++i)
462 {
463 if ((i < low) || (i > high))
464 {
465 EValsRe_[i] = H_[i][i];
466 EValsIm_[i] = Zero;
467 }
468
469 for (label j = max(i - 1, 0); j < nn; ++j)
470 {
471 norm += mag(H_[i][j]);
472 }
473 }
474
475 label iter = 0;
476
477 while (n >= low)
478 {
479 // Look for single SMALL sub-diagonal element
480 label l = n;
481
482 while (l > low)
483 {
484 s = mag(H_[l - 1][l - 1]) + mag(H_[l][l]);
485
486 if (s == 0.0)
487 {
488 s = norm;
489 }
490
491 if (mag(H_[l][l - 1]) < eps*s)
492 {
493 break;
494 }
495
496 l--;
497 }
498
499 // Check for convergence
500 if (l == n) // One root found
501 {
502 H_[n][n] = H_[n][n] + exshift;
503 EValsRe_[n] = H_[n][n];
504 EValsIm_[n] = Zero;
505 --n;
506 iter = 0;
507 }
508 else if (l == n - 1) // Two roots found
509 {
510 w = H_[n][n - 1]*H_[n - 1][n];
511 p = (H_[n - 1][n - 1] - H_[n][n])/2.0;
512 q = p*p + w;
513 z = Foam::sqrt(mag(q));
514 H_[n][n] += exshift;
515 H_[n - 1][n - 1] += exshift;
516 x = H_[n][n];
517
518 // Scalar pair
519 if (q >= 0)
520 {
521 if (p >= 0)
522 {
523 z = p + z;
524 }
525 else
526 {
527 z = p - z;
528 }
529
530 EValsRe_[n - 1] = x + z;
531 EValsRe_[n] = EValsRe_[n - 1];
532
533 if (z != 0.0)
534 {
535 EValsRe_[n] = x - w/z;
536 }
537
538 EValsIm_[n - 1] = Zero;
539 EValsIm_[n] = Zero;
540 x = H_[n][n - 1];
541 s = mag(x) + mag(z);
542 p = x/s;
543 q = z/s;
544 r = Foam::sqrt(p*p + q*q);
545 p /= r;
546 q /= r;
547
548 // Row modification
549 for (label j = n - 1; j < nn; ++j)
550 {
551 z = H_[n - 1][j];
552 H_[n - 1][j] = q*z + p*H_[n][j];
553 H_[n][j] = q*H_[n][j] - p*z;
554 }
555
556 // Column modification
557 for (label i = 0; i <= n; ++i)
558 {
559 z = H_[i][n - 1];
560 H_[i][n - 1] = q*z + p*H_[i][n];
561 H_[i][n] = q*H_[i][n] - p*z;
562 }
563
564 // Accumulate transformations
565 for (label i = low; i <= high; ++i)
566 {
567 z = EVecs_[i][n - 1];
568 EVecs_[i][n - 1] = q*z + p*EVecs_[i][n];
569 EVecs_[i][n] = q*EVecs_[i][n] - p*z;
570 }
571 }
572 else // Complex pair of roots
573 {
574 EValsRe_[n - 1] = x + p;
575 EValsRe_[n] = x + p;
576 EValsIm_[n - 1] = z;
577 EValsIm_[n] = -z;
578 }
579
580 n -= 2;
581 iter = 0;
582 }
583 else // No convergence yet
584 {
585 // Form shift
586 x = H_[n][n];
587 y = Zero;
588 w = Zero;
589
590 if (l < n)
591 {
592 y = H_[n - 1][n - 1];
593 w = H_[n][n - 1]*H_[n - 1][n];
594 }
595
596 // Wilkinson's original ad-hoc shift
597 if (iter == 10)
598 {
599 exshift += x;
600 for (label i = low; i <= n; ++i)
601 {
602 H_[i][i] -= x;
603 }
604
605 s = mag(H_[n][n - 1]) + mag(H_[n - 1][n - 2]);
606 x = 0.75*s;
607 y = 0.75*s;
608 w = -0.4375*s*s;
609 }
610
611 // New ad hoc shift
612 if (iter == 30)
613 {
614 s = (y - x)/2.0;
615 s = s*s + w;
616
617 if (s > 0)
618 {
619 s = Foam::sqrt(s);
620
621 if (y < x)
622 {
623 s = -s;
624 }
625
626 s = x - w/((y - x)/2.0 + s);
627
628 for (label i = low; i <= n; ++i)
629 {
630 H_[i][i] -= s;
631 }
632
633 exshift += s;
634 x = 0.964;
635 y = 0.964;
636 w = 0.964;
637 }
638 }
639
640 iter += 1;
641
642 // Look for two consecutive SMALL sub-diagonal elements
643 label m = n - 2;
644
645 while (m >= l)
646 {
647 z = H_[m][m];
648 r = x - z;
649 s = y - z;
650 p = (r*s - w)/H_[m + 1][m] + H_[m][m + 1];
651 q = H_[m + 1][m + 1] - z - r - s;
652 r = H_[m + 2][m + 1];
653 s = mag(p) + mag(q) + mag(r);
654 p /= s;
655 q /= s;
656 r /= s;
657
658 if (m == l)
659 {
660 break;
661 }
662
663 if
664 (
665 mag(H_[m][m - 1])*(mag(q) + mag(r))
666 < eps*(mag(p)*(mag(H_[m - 1][m - 1])
667 + mag(z) + mag(H_[m + 1][m + 1])))
668 )
669 {
670 break;
671 }
672
673 --m;
674 }
675
676 for (label i = m + 2; i <= n; ++i)
677 {
678 H_[i][i - 2] = Zero;
679
680 if (i > m + 2)
681 {
682 H_[i][i - 3] = Zero;
683 }
684 }
685
686 // Double QR step involving rows l:n and columns m:n
687 for (label k = m; k <= n - 1; ++k)
688 {
689 label notlast = (k != n - 1);
690
691 if (k != m)
692 {
693 p = H_[k][k - 1];
694 q = H_[k + 1][k - 1];
695 r = (notlast ? H_[k + 2][k - 1] : 0.0);
696 x = mag(p) + mag(q) + mag(r);
697
698 if (x != 0.0)
699 {
700 p /= x;
701 q /= x;
702 r /= x;
703 }
704 }
705
706 if (x == 0.0)
707 {
708 break;
709 }
710
711 s = Foam::sqrt(p*p + q*q + r*r);
712
713 if (p < 0)
714 {
715 s = -s;
716 }
717
718 if (s != 0)
719 {
720 if (k != m)
721 {
722 H_[k][k - 1] = -s*x;
723 }
724 else if (l != m)
725 {
726 H_[k][k - 1] = -H_[k][k - 1];
727 }
728
729 p = p + s;
730 x = p/s;
731 y = q/s;
732 z = r/s;
733 q /= p;
734 r /= p;
735
736 // Row modification
737 for (label j = k; j < nn; ++j)
738 {
739 p = H_[k][j] + q*H_[k + 1][j];
740
741 if (notlast)
742 {
743 p += r*H_[k + 2][j];
744 H_[k + 2][j] -= p*z;
745 }
746
747 H_[k][j] -= p*x;
748 H_[k + 1][j] -= p*y;
749 }
750
751 // Column modification
752 for (label i = 0; i <= min(n, k + 3); ++i)
753 {
754 p = x*H_[i][k] + y*H_[i][k + 1];
755
756 if (notlast)
757 {
758 p += z*H_[i][k + 2];
759 H_[i][k + 2] -= p*r;
760 }
761
762 H_[i][k] -= p;
763 H_[i][k + 1] -= p*q;
764 }
765
766 // Accumulate transformations
767 for (label i = low; i <= high; ++i)
768 {
769 p = x*EVecs_[i][k] + y*EVecs_[i][k + 1];
770
771 if (notlast)
772 {
773 p += z*EVecs_[i][k + 2];
774 EVecs_[i][k + 2] -= p*r;
775 }
776
777 EVecs_[i][k] -= p;
778 EVecs_[i][k + 1] -= p*q;
779 }
780 }
781 }
782 }
783 }
784
785 // Backsubstitute to find vectors of upper triangular form
786 if (norm == 0.0)
787 {
788 return;
789 }
790
791 for (n = nn-1; n >= 0; --n)
792 {
793 p = EValsRe_[n];
794 q = EValsIm_[n];
795
796 // scalar vector
797 if (q == 0)
798 {
799 label l = n;
800 H_[n][n] = cmptType(1);
801
802 for (label i = n-1; i >= 0; --i)
803 {
804 w = H_[i][i] - p;
805 r = Zero;
806
807 for (label j = l; j <= n; ++j)
808 {
809 r += H_[i][j]*H_[j][n];
810 }
811
812 if (EValsIm_[i] < 0.0)
813 {
814 z = w;
815 s = r;
816 }
817 else
818 {
819 l = i;
820
821 if (EValsIm_[i] == 0.0)
822 {
823 if (w != 0.0)
824 {
825 H_[i][n] = -r/w;
826 }
827 else
828 {
829 H_[i][n] = -r/(eps*norm);
830 }
831 }
832 else // Solve real equations
833 {
834 x = H_[i][i + 1];
835 y = H_[i + 1][i];
836 q = (EValsRe_[i] - p)*(EValsRe_[i] - p)
837 + EValsIm_[i]*EValsIm_[i];
838
839 t = (x*s - z*r)/q;
840 H_[i][n] = t;
841
842 if (mag(x) > mag(z))
843 {
844 H_[i + 1][n] = (-r - w*t)/x;
845 }
846 else
847 {
848 H_[i + 1][n] = (-s - y*t)/z;
849 }
850 }
851
852 // Overflow control
853 t = mag(H_[i][n]);
854
855 if ((eps*t)*t > 1)
856 {
857 for (label j = i; j <= n; ++j)
858 {
859 H_[j][n] /= t;
860 }
861 }
862 }
863 }
864 }
865 else if (q < 0) // Complex vector
866 {
867 label l = n - 1;
868
869 // Last vector component imaginary so matrix is triangular
870 if (mag(H_[n][n - 1]) > mag(H_[n - 1][n]))
871 {
872 H_[n - 1][n - 1] = q/H_[n][n - 1];
873 H_[n - 1][n] = -(H_[n][n] - p)/H_[n][n - 1];
874 }
875 else
876 {
877 complex cDiv = complex(0.0, -H_[n - 1][n])
878 /complex(H_[n - 1][n-1]-p, q);
879
880 H_[n - 1][n - 1] = cDiv.Re();
881 H_[n - 1][n] = cDiv.Im();
882 }
883
884 H_[n][n - 1] = Zero;
885 H_[n][n] = cmptType(1);
886
887 for (label i = n - 2; i >= 0; --i)
888 {
889 cmptType ra, sa, vr, vi;
890 ra = Zero;
891 sa = Zero;
892
893 for (label j = l; j <= n; ++j)
894 {
895 ra += H_[i][j]*H_[j][n-1];
896 sa += H_[i][j]*H_[j][n];
897 }
898
899 w = H_[i][i] - p;
900
901 if (EValsIm_[i] < 0.0)
902 {
903 z = w;
904 r = ra;
905 s = sa;
906 }
907 else
908 {
909 l = i;
910
911 if (EValsIm_[i] == 0)
912 {
913 complex cDiv = complex(-ra, -sa)/complex(w, q);
914 H_[i][n - 1] = cDiv.Re();
915 H_[i][n] = cDiv.Im();
916 }
917 else
918 {
919 // Solve complex equations
920 x = H_[i][i + 1];
921 y = H_[i + 1][i];
922 vr = (EValsRe_[i] - p)*(EValsRe_[i] - p)
923 + EValsIm_[i]*EValsIm_[i] - q*q;
924
925 vi = 2.0*(EValsRe_[i] - p)*q;
926
927 if ((vr == 0.0) && (vi == 0.0))
928 {
929 vr = eps*norm*(mag(w) + mag(q) + mag(x) + mag(y)
930 + mag(z));
931 }
932
933 complex cDiv =
934 complex(x*r - z*ra + q*sa, x*s - z*sa - q*ra)
935 /complex(vr, vi);
936
937 H_[i][n - 1] = cDiv.Re();
938 H_[i][n] = cDiv.Im();
939
940 if (mag(x) > (mag(z) + mag(q)))
941 {
942 H_[i + 1][n - 1] = (-ra - w*H_[i][n - 1]
943 + q*H_[i][n])/x;
944
945 H_[i + 1][n] = (-sa - w*H_[i][n]
946 - q*H_[i][n - 1])/x;
947 }
948 else
949 {
950 complex cDiv = complex(-r - y*H_[i][n - 1], -s
951 - y*H_[i][n])/complex(z, q);
952
953 H_[i + 1][n - 1] = cDiv.Re();
954 H_[i + 1][n] = cDiv.Im();
955 }
956 }
957
958 // Overflow control
959 t = max(mag(H_[i][n - 1]), mag(H_[i][n]));
960
961 if ((eps*t)*t > 1)
962 {
963 for (label j = i; j <= n; ++j)
964 {
965 H_[j][n - 1] /= t;
966 H_[j][n] /= t;
967 }
968 }
969 }
970 }
971 }
972 }
973
974 // Vectors of isolated roots
975 for (label i = 0; i < nn; ++i)
976 {
977 if (i < low || i > high)
978 {
979 for (label j = i; j < nn; ++j)
980 {
981 EVecs_[i][j] = H_[i][j];
982 }
983 }
984 }
985
986 // Back transformation to get eigenvectors of original matrix
987 for (label j = nn - 1; j >= low; --j)
988 {
989 for (label i = low; i <= high; ++i)
990 {
991 z = Zero;
992
993 for (label k = low; k <= min(j, high); ++k)
994 {
995 z = z + EVecs_[i][k]*H_[k][j];
996 }
997
998 EVecs_[i][j] = z;
999 }
1000 }
1001}
1002
1003
1004// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1005
1006template<class cmptType>
1008:
1009 n_(A.n()),
1010 EValsRe_(n_, Zero),
1011 EValsIm_(n_, Zero),
1012 EVecs_(n_, Zero),
1013 H_()
1014{
1015 if (n_ <= 0)
1016 {
1018 << "Input matrix has zero size."
1019 << abort(FatalError);
1020 }
1021
1022 if (A.symmetric())
1023 {
1024 EVecs_ = A;
1025 tridiagonaliseSymmMatrix();
1026 symmTridiagonalQL();
1027 }
1028 else
1029 {
1030 H_ = A;
1031 Hessenberg();
1032 realSchur();
1033 }
1034}
1035
1036
1037template<class cmptType>
1039(
1041 bool symmetric
1042)
1043:
1044 n_(A.n()),
1045 EValsRe_(n_, Zero),
1046 EValsIm_(n_, Zero),
1047 EVecs_(n_, Zero),
1048 H_()
1049{
1050 if (n_ <= 0)
1051 {
1053 << "Input matrix has zero size."
1054 << abort(FatalError);
1055 }
1056
1057 if (symmetric)
1058 {
1059 EVecs_ = A;
1060 tridiagonaliseSymmMatrix();
1061 symmTridiagonalQL();
1062 }
1063 else
1064 {
1065 H_ = A;
1066 Hessenberg();
1067 realSchur();
1068 }
1069}
1070
1071
1072// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1073
1074template<class cmptType>
1077{
1078 SquareMatrix<complex> EVecs(EVecs_.n());
1079
1080 std::transform
1081 (
1082 EVecs_.cbegin(),
1083 EVecs_.cend(),
1084 EVecs.begin(),
1085 [&](const cmptType& x){ return complex(x); }
1086 );
1087
1088 for (label i = 0; i < EValsIm_.size(); ++i)
1089 {
1090 if (mag(EValsIm_[i]) > VSMALL)
1091 {
1092 for (label j = 0; j < EVecs.m(); ++j)
1093 {
1094 EVecs(j, i) = complex(EVecs_(j, i), EVecs_(j, i+1));
1095 EVecs(j, i+1) = EVecs(j, i).conjugate();
1096 }
1097 ++i;
1098 }
1099 }
1100
1101 return EVecs;
1102}
1103
1104
1105// ************************************************************************* //
static const Foam::dimensionedScalar A("", Foam::dimPressure, 611.21)
scalar y
label k
label n
Y[inertIndex] max(0.0)
const uniformDimensionedVectorField & g
EigenMatrix (i.e. eigendecomposition or spectral decomposition) decomposes a diagonalisable nonsymmet...
Definition: EigenMatrix.H:179
EigenMatrix()=delete
No default construct.
const SquareMatrix< complex > complexEVecs() const
Return right eigenvectors in unpacked form.
Definition: EigenMatrix.C:1076
iterator begin() noexcept
Return an iterator to begin traversing a Matrix.
Definition: MatrixI.H:535
label m() const noexcept
The number of rows.
Definition: MatrixI.H:96
A templated (N x N) square matrix of objects of <Type>, containing N*N elements, derived from Matrix.
Definition: SquareMatrix.H:66
A complex number, similar to the C++ complex type.
Definition: complex.H:83
volScalarField & p
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const dimensionedScalar c2
Second radiation constant: default SI units: [m.K].
const dimensionedScalar c
Speed of light in a vacuum.
@ complex
Definition: Roots.H:57
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
dimensionedScalar hypot(const dimensionedScalar &x, const dimensionedScalar &y)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
errorManip< error > abort(error &err)
Definition: errorManip.H:144
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
labelList f(nPoints)
volScalarField & h