OpenMD
3.2
Molecular Dynamics in the Open
Toggle main menu visibility
Loading...
Searching...
No Matches
RealSymmetricTridiagonal.hpp
1
/*
2
* Copyright (c) 2004-present, The University of Notre Dame. All rights
3
* reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
7
*
8
* 1. Redistributions of source code must retain the above copyright notice,
9
* this list of conditions and the following disclaimer.
10
*
11
* 2. Redistributions in binary form must reproduce the above copyright notice,
12
* this list of conditions and the following disclaimer in the documentation
13
* and/or other materials provided with the distribution.
14
*
15
* 3. Neither the name of the copyright holder nor the names of its
16
* contributors may be used to endorse or promote products derived from
17
* this software without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
* POSSIBILITY OF SUCH DAMAGE.
30
*
31
* SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32
* research, please cite the following paper when you publish your work:
33
*
34
* [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35
*
36
* Good starting points for code and simulation methodology are:
37
*
38
* [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39
* [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40
* [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41
* [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42
* [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43
* [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44
* [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45
* [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46
*/
47
48
#ifndef MATH_REALSYMMETRICTRIDIAGONAL_HPP
49
#define MATH_REALSYMMETRICTRIDIAGONAL_HPP
50
51
#include <config.h>
52
53
#include <algorithm>
54
55
#include "
math/DynamicRectMatrix.hpp
"
56
// for min(), max() below
57
#include <cmath>
58
// for abs() below
59
60
namespace
OpenMD
{
61
62
/**
63
64
Computes eigenvalues and eigenvectors of a real (non-complex)
65
symmetric tridiagonal matrix by the QL method.
66
**/
67
68
template
<
typename
Real>
69
class
RealSymmetricTridiagonal
{
70
/** Row and column dimension (square matrix). */
71
int
n;
72
73
DynamicVector<Real>
d;
74
DynamicVector<Real>
e;
75
76
/** Array for internal storage of eigenvectors. */
77
DynamicRectMatrix<Real>
V;
78
79
// Symmetric tridiagonal QL algorithm.
80
81
void
tql2() {
82
// This is derived from the Algol procedures tql2, by
83
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
84
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
85
// Fortran subroutine in EISPACK.
86
87
for
(
int
i = 1; i < n; i++) {
88
e(i - 1) = e(i);
89
}
90
e(n - 1) = 0.0;
91
92
Real f = 0.0;
93
Real tst1 = 0.0;
94
Real eps = std::pow(2.0, -52.0);
95
for
(
int
l = 0; l < n; l++) {
96
// Find small subdiagonal element
97
98
tst1 = std::max(tst1, std::abs(d(l)) + std::abs(e(l)));
99
int
m = l;
100
101
// Original while-loop from Java code
102
while
(m < n) {
103
if
(std::abs(e(m)) <= eps * tst1) {
break
; }
104
m++;
105
}
106
107
// If m == l, d(l) is an eigenvalue,
108
// otherwise, iterate.
109
110
if
(m > l) {
111
int
iter = 0;
112
do
{
113
iter = iter + 1;
// (Could check iteration count here.)
114
115
// Compute implicit shift
116
117
Real g = d(l);
118
Real p = (d(l + 1) - g) / (2.0 * e(l));
119
Real r = std::hypot(p, 1.0);
120
if
(p < 0) { r = -r; }
121
d(l) = e(l) / (p + r);
122
d(l + 1) = e(l) * (p + r);
123
Real dl1 = d(l + 1);
124
Real h = g - d(l);
125
for
(
int
i = l + 2; i < n; i++) {
126
d(i) -= h;
127
}
128
f = f + h;
129
130
// Implicit QL transformation.
131
132
p = d(m);
133
Real c = 1.0;
134
Real c2 = c;
135
Real c3 = c;
136
Real el1 = e(l + 1);
137
Real s = 0.0;
138
Real s2 = 0.0;
139
for
(
int
i = m - 1; i >= l; i--) {
140
c3 = c2;
141
c2 = c;
142
s2 = s;
143
g = c * e(i);
144
h = c * p;
145
r = std::hypot(p, e(i));
146
e(i + 1) = s * r;
147
s = e(i) / r;
148
c = p / r;
149
p = c * d(i) - s * g;
150
d(i + 1) = h + s * (c * g + s * d(i));
151
152
// Accumulate transformation.
153
154
for
(
int
k = 0; k < n; k++) {
155
h = V(k, i + 1);
156
V(k, i + 1) = s * V(k, i) + c * h;
157
V(k, i) = c * V(k, i) - s * h;
158
}
159
}
160
p = -s * s2 * c3 * el1 * e(l) / dl1;
161
e(l) = s * p;
162
d(l) = c * p;
163
164
// Check for convergence.
165
166
}
while
(std::abs(e(l)) > eps * tst1);
167
}
168
d(l) = d(l) + f;
169
e(l) = 0.0;
170
}
171
172
// Sort eigenvalues and corresponding vectors.
173
174
for
(
int
i = 0; i < n - 1; i++) {
175
int
k = i;
176
Real p = d(i);
177
for
(
int
j = i + 1; j < n; j++) {
178
if
(d(j) < p) {
179
k = j;
180
p = d(j);
181
}
182
}
183
if
(k != i) {
184
d(k) = d(i);
185
d(i) = p;
186
for
(
int
j = 0; j < n; j++) {
187
p = V(j, i);
188
V(j, i) = V(j, k);
189
V(j, k) = p;
190
}
191
}
192
}
193
}
194
195
public
:
196
/** Construct the eigenvalue decomposition
197
198
@param diagonals the diagonal elements of the input matrix.
199
@param subdiagonals the subdiagonal elements of the input matrix in its
200
last n-1 positions. subdiagonals[0] is arbitrary.
201
*/
202
RealSymmetricTridiagonal
(
const
DynamicVector<Real>
& diagonals,
203
const
DynamicVector<Real>
& subdiagonals) {
204
n = diagonals.size();
205
V =
DynamicRectMatrix<Real>
(n, n, 0.0);
206
d = diagonals;
207
e = subdiagonals;
208
209
for
(
int
i = 0; i < n; i++) {
210
V(i, i) = 1.0;
211
}
212
// Diagonalize.
213
tql2();
214
}
215
216
/** Return the eigenvector matrix
217
@return V
218
*/
219
void
getEigenvectors
(
DynamicRectMatrix<Real>
& V_) {
220
V_ = V;
221
return
;
222
}
223
224
/** Return the real parts of the eigenvalues
225
@return real(diag(D))
226
*/
227
void
getEigenvalues
(
DynamicVector<Real>
& d_) {
228
d_ = d;
229
return
;
230
}
231
};
232
}
// namespace OpenMD
233
234
#endif
// MATH_REALSYMMETRICTRIDIAGONAL_HPP
DynamicRectMatrix.hpp
OpenMD::DynamicRectMatrix
Rectangular matrix class with contiguous flat storage.
Definition
DynamicRectMatrix.hpp:78
OpenMD::DynamicVector
Dynamically-sized vector class.
Definition
DynamicVector.hpp:74
OpenMD::RealSymmetricTridiagonal::getEigenvectors
void getEigenvectors(DynamicRectMatrix< Real > &V_)
Return the eigenvector matrix.
Definition
RealSymmetricTridiagonal.hpp:219
OpenMD::RealSymmetricTridiagonal::RealSymmetricTridiagonal
RealSymmetricTridiagonal(const DynamicVector< Real > &diagonals, const DynamicVector< Real > &subdiagonals)
Construct the eigenvalue decomposition.
Definition
RealSymmetricTridiagonal.hpp:202
OpenMD::RealSymmetricTridiagonal::getEigenvalues
void getEigenvalues(DynamicVector< Real > &d_)
Return the real parts of the eigenvalues.
Definition
RealSymmetricTridiagonal.hpp:227
OpenMD
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Definition
ActionCorrFunc.cpp:63
math
RealSymmetricTridiagonal.hpp
Generated on
for OpenMD by
1.17.0