71 if (number_of_orbitals == 0)
75 transform.
eigenvalues.assign(
static_cast<size_t>(number_of_orbitals), 0.0);
76 int work_size = std::max(1, 2 * number_of_orbitals - 1);
77 std::vector<Complex> work(work_size);
78 std::vector<Real> rwork(
static_cast<size_t>(std::max(1, 3 * number_of_orbitals - 2)));
85 reinterpret_cast<std::complex<double>*
>(overlap_column_major.data()),
88 reinterpret_cast<std::complex<double>*
>(work.data()),
93 throw std::runtime_error(
"compute_lowdin_transform: ZHEEV failed, info=" +
94 std::to_string(info));
97 for (
int k = 0; k < number_of_orbitals; k++) {
100 throw std::runtime_error(
101 "compute_lowdin_transform: near-singular overlap matrix (eigenvalue " +
102 std::to_string(transform.
eigenvalues[
static_cast<size_t>(k)]) +
103 ") -- atomic orbitals are not linearly independent");
106 transform.
eigenvectors = std::move(overlap_column_major);
110 static_cast<size_t>(number_of_orbitals) * number_of_orbitals,
Complex(0.0, 0.0));
111 for (
int k = 0; k < number_of_orbitals; k++) {
112 Real inverse_square_root_eigenvalue =
113 1.0 / std::sqrt(transform.
eigenvalues[
static_cast<size_t>(k)]);
114 for (
int a = 0; a < number_of_orbitals; a++) {
116 transform.
eigenvectors[
static_cast<size_t>(a + k * number_of_orbitals)] *
117 inverse_square_root_eigenvalue;
118 for (
int b = 0; b < number_of_orbitals; b++) {
122 transform.
eigenvectors[
static_cast<size_t>(b + k * number_of_orbitals)]);
137 int number_of_orbitals =
static_cast<int>(orbitals.size());
138 if (number_of_orbitals == 0)
140 int number_of_plane_waves =
static_cast<int>(orbitals[0].size());
143 std::vector<Complex> overlap_column_major(
static_cast<size_t>(number_of_orbitals) *
145 for (
int column = 0; column < number_of_orbitals; column++) {
146 for (
int row = 0; row < number_of_orbitals; row++) {
148 for (
int g_index = 0; g_index < number_of_plane_waves; g_index++) {
149 value += std::conj(orbitals[row][g_index]) * orbitals[column][g_index];
151 overlap_column_major[
static_cast<size_t>(row + column * number_of_orbitals)] = value;
154 return overlap_column_major;
164 std::vector<Complex> overlap_column_major) {
165 int number_of_orbitals =
static_cast<int>(orbitals.size());
166 if (number_of_orbitals == 0)
168 int number_of_plane_waves =
static_cast<int>(orbitals[0].size());
169 size_t expected_overlap_size =
static_cast<size_t>(number_of_orbitals) * number_of_orbitals;
170 if (overlap_column_major.size() != expected_overlap_size) {
171 throw std::runtime_error(
"lowdin_orthogonalize_orbitals: overlap matrix has " +
172 std::to_string(overlap_column_major.size()) +
173 " elements, expected " + std::to_string(expected_overlap_size));
179 std::vector<std::vector<Complex>> orthogonalized_orbitals(
180 number_of_orbitals, std::vector<Complex>(number_of_plane_waves,
Complex(0.0, 0.0)));
181 for (
int i = 0; i < number_of_orbitals; i++) {
182 for (
int j = 0; j < number_of_orbitals; j++) {
184 transform.inverse_square_root[
static_cast<size_t>(j + i * number_of_orbitals)];
185 for (
int g_index = 0; g_index < number_of_plane_waves; g_index++) {
186 orthogonalized_orbitals[i][g_index] += weight * orbitals[j][g_index];
191 orbitals = std::move(orthogonalized_orbitals);
222 const std::vector<Complex>& overlap_derivative) {
224 size_t element_count =
static_cast<size_t>(number_of_orbitals) * number_of_orbitals;
225 if (overlap_derivative.size() != element_count) {
226 throw std::runtime_error(
"lowdin_inverse_square_root_derivative: overlap derivative has " +
227 std::to_string(overlap_derivative.size()) +
228 " elements, expected " + std::to_string(element_count));
230 std::vector<Complex> result(element_count,
Complex(0.0, 0.0));
231 if (number_of_orbitals == 0)
236 auto index = [number_of_orbitals](
int row,
int column) {
237 return static_cast<size_t>(row + column * number_of_orbitals);
241 std::vector<Complex> right_product(element_count,
Complex(0.0, 0.0));
242 for (
int column = 0; column < number_of_orbitals; column++)
243 for (
int inner = 0; inner < number_of_orbitals; inner++) {
244 Complex eigenvector_component = eigenvectors[index(inner, column)];
245 if (eigenvector_component ==
Complex(0.0, 0.0))
247 for (
int row = 0; row < number_of_orbitals; row++)
248 right_product[index(row, column)] +=
249 overlap_derivative[index(row, inner)] * eigenvector_component;
251 std::vector<Complex> eigenbasis_derivative(element_count,
Complex(0.0, 0.0));
252 for (
int column = 0; column < number_of_orbitals; column++)
253 for (
int row = 0; row < number_of_orbitals; row++) {
255 for (
int inner = 0; inner < number_of_orbitals; inner++)
256 accumulated += std::conj(eigenvectors[index(inner, row)]) *
257 right_product[index(inner, column)];
258 eigenbasis_derivative[index(row, column)] = accumulated;
262 std::vector<Real> square_root_eigenvalues(
static_cast<size_t>(number_of_orbitals));
263 for (
int k = 0; k < number_of_orbitals; k++)
264 square_root_eigenvalues[
static_cast<size_t>(k)] =
265 std::sqrt(eigenvalues[
static_cast<size_t>(k)]);
266 for (
int column = 0; column < number_of_orbitals; column++)
267 for (
int row = 0; row < number_of_orbitals; row++)
268 eigenbasis_derivative[index(row, column)] /=
269 eigenvalues[
static_cast<size_t>(row)] *
270 square_root_eigenvalues[
static_cast<size_t>(column)] +
271 eigenvalues[
static_cast<size_t>(column)] *
272 square_root_eigenvalues[
static_cast<size_t>(row)];
274 std::vector<Complex> left_product(element_count,
Complex(0.0, 0.0));
275 for (
int column = 0; column < number_of_orbitals; column++)
276 for (
int inner = 0; inner < number_of_orbitals; inner++) {
277 Complex eigenvector_component = std::conj(eigenvectors[index(column, inner)]);
278 if (eigenvector_component ==
Complex(0.0, 0.0))
280 for (
int row = 0; row < number_of_orbitals; row++)
281 left_product[index(row, column)] +=
282 eigenbasis_derivative[index(row, inner)] * eigenvector_component;
284 for (
int column = 0; column < number_of_orbitals; column++)
285 for (
int row = 0; row < number_of_orbitals; row++) {
287 for (
int inner = 0; inner < number_of_orbitals; inner++)
288 accumulated += eigenvectors[index(row, inner)] * left_product[index(inner, column)];
289 result[index(row, column)] = -accumulated;
void zheev_(const char *jobz, const char *uplo, const int *n, std::complex< double > *a, const int *lda, double *w, std::complex< double > *work, const int *lwork, double *rwork, int *info)