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