SIRIUS 7.5.0
Electronic structure library and applications
eigenproblem.cpp
1#include "eigenproblem.hpp"
2
3#if defined(SIRIUS_ELPA)
4#include <elpa/elpa.h>
5#endif
6
7#if defined(SIRIUS_DLAF)
8#include <dlaf_c/init.h>
9#endif
10
11namespace sirius {
12
13namespace la {
14
15#if defined(SIRIUS_ELPA)
16
17template <typename M>
18void setup_handler(elpa_t& handle__, int stage__, M const& m__, int na__, int nev__)
19{
20 int error;
21 int nt = omp_get_max_threads();
22
23 elpa_set_integer(handle__, "na", na__, &error);
24 elpa_set_integer(handle__, "nev", nev__, &error);
25 elpa_set_integer(handle__, "local_nrows", m__.num_rows_local(), &error);
26 elpa_set_integer(handle__, "local_ncols", m__.num_cols_local(), &error);
27 elpa_set_integer(handle__, "nblk", m__.bs_row(), &error);
28 elpa_set_integer(handle__, "mpi_comm_parent", MPI_Comm_c2f(m__.blacs_grid().comm().native()), &error);
29 elpa_set_integer(handle__, "process_row", m__.blacs_grid().comm_row().rank(), &error);
30 elpa_set_integer(handle__, "process_col", m__.blacs_grid().comm_col().rank(), &error);
31 elpa_set_integer(handle__, "blacs_context", m__.blacs_grid().context(), &error);
32 elpa_set_integer(handle__, "omp_threads", nt, &error);
33 if (acc::num_devices() != 0) {
34 elpa_set_integer(handle__, "nvidia-gpu", 1, &error);
35 }
36 if (stage__ == 1) {
37 elpa_set_integer(handle__, "solver", ELPA_SOLVER_1STAGE, &error);
38 } else {
39 elpa_set_integer(handle__, "solver", ELPA_SOLVER_2STAGE, &error);
40 }
41 elpa_setup(handle__);
42}
43
44Eigensolver_elpa::Eigensolver_elpa(int stage__)
45 : Eigensolver(ev_solver_t::elpa, true, sddk::memory_t::host, sddk::memory_t::host)
46 , stage_(stage__)
47{
48 if (!(stage_ == 1 || stage_ == 2)) {
49 RTE_THROW("wrong type of ELPA solver");
50 }
51}
52
54{
55 if (elpa_init(20170403) != ELPA_OK) {
56 RTE_THROW("ELPA API version not supported");
57 }
58}
59
60void Eigensolver_elpa::finalize()
61{
62 int ierr;
63 elpa_uninit(&ierr);
64}
65
66/// Solve a generalized eigen-value problem for N lowest eigen-pairs.
67int Eigensolver_elpa::solve(ftn_int matrix_size__, ftn_int nev__, la::dmatrix<double>& A__, la::dmatrix<double>& B__,
68 double* eval__, la::dmatrix<double>& Z__)
69{
70 PROFILE("Eigensolver_elpa|solve_gen");
71
72 int nt = omp_get_max_threads();
73
74 if (A__.num_cols_local() != Z__.num_cols_local()) {
75 RTE_THROW("number of columns in A and Z don't match");
76 }
77
78 PROFILE_START("Eigensolver_elpa|solve_gen|setup");
79
80 int error;
81 elpa_t handle;
82
83 handle = elpa_allocate(&error);
84 if (error != ELPA_OK) {
85 return 1;
86 }
87 setup_handler(handle, stage_, A__, matrix_size__, nev__);
88
89 PROFILE_STOP("Eigensolver_elpa|solve_gen|setup");
90
91 auto& mph = get_memory_pool(sddk::memory_t::host);
92
93 auto w = mph.get_unique_ptr<double>(matrix_size__);
94
95 elpa_generalized_eigenvectors_d(handle, A__.at(sddk::memory_t::host), B__.at(sddk::memory_t::host),
96 w.get(), Z__.at(sddk::memory_t::host), 0, &error);
97
98 if (error != ELPA_OK) {
99 elpa_deallocate(handle, &error);
100 return 1;
101 }
102
103 elpa_deallocate(handle, &error);
104
105 std::copy(w.get(), w.get() + nev__, eval__);
106
107 if (nt != omp_get_max_threads()) {
108 std::stringstream s;
109 s << "number of OMP threads was changed by elpa" << std::endl
110 << " initial number of threads : " << nt << std::endl
111 << " new number of threads : " << omp_get_max_threads();
112 RTE_THROW(s);
113 }
114
115 return 0;
116
117 //to_std(matrix_size__, A__, B__, Z__);
118
119 ///* solve a standard problem */
120 //int result = this->solve(matrix_size__, nev__, A__, eval__, Z__);
121 //if (result) {
122 // return result;
123 //}
124
125 //bt(matrix_size__, nev__, A__, B__, Z__);
126 //return 0;
127}
128
129/// Solve a generalized eigen-value problem for N lowest eigen-pairs.
130int Eigensolver_elpa::solve(ftn_int matrix_size__, ftn_int nev__, la::dmatrix<std::complex<double>>& A__, la::dmatrix<std::complex<double>>& B__,
131 double* eval__, la::dmatrix<std::complex<double>>& Z__)
132{
133 PROFILE("Eigensolver_elpa|solve_gen");
134
135 int nt = omp_get_max_threads();
136
137 if (A__.num_cols_local() != Z__.num_cols_local()) {
138 RTE_THROW("number of columns in A and Z don't match");
139 }
140
141 PROFILE_START("Eigensolver_elpa|solve_gen|setup");
142
143 int error;
144 elpa_t handle;
145
146 handle = elpa_allocate(&error);
147 if (error != ELPA_OK) {
148 return 1;
149 }
150 setup_handler(handle, stage_, A__, matrix_size__, nev__);
151
152 PROFILE_STOP("Eigensolver_elpa|solve_gen|setup");
153
154 auto& mph = get_memory_pool(sddk::memory_t::host);
155
156 auto w = mph.get_unique_ptr<double>(matrix_size__);
157
158 elpa_generalized_eigenvectors_dc(handle, A__.at(sddk::memory_t::host), B__.at(sddk::memory_t::host),
159 w.get(), Z__.at(sddk::memory_t::host), 0, &error);
160
161 if (error != ELPA_OK) {
162 elpa_deallocate(handle, &error);
163 return 1;
164 }
165
166 elpa_deallocate(handle, &error);
167
168 std::copy(w.get(), w.get() + nev__, eval__);
169
170 if (nt != omp_get_max_threads()) {
171 std::stringstream s;
172 s << "number of OMP threads was changed by elpa" << std::endl
173 << " initial number of threads : " << nt << std::endl
174 << " new number of threads : " << omp_get_max_threads();
175 RTE_THROW(s);
176 }
177
178 return 0;
179 //to_std(matrix_size__, A__, B__, Z__);
180
181 ///* solve a standard problem */
182 //int result = this->solve(matrix_size__, nev__, A__, eval__, Z__);
183 //if (result) {
184 // return result;
185 //}
186
187 //bt(matrix_size__, nev__, A__, B__, Z__);
188 //return 0;
189}
190
191/// Solve a generalized eigen-value problem for all eigen-pairs.
192int Eigensolver_elpa::solve(ftn_int matrix_size__, la::dmatrix<double>& A__, la::dmatrix<double>& B__, double* eval__, la::dmatrix<double>& Z__)
193{
194 return solve(matrix_size__, matrix_size__, A__, B__, eval__, Z__);
195}
196
197/// Solve a generalized eigen-value problem for all eigen-pairs.
198int Eigensolver_elpa::solve(ftn_int matrix_size__, la::dmatrix<std::complex<double>>& A__, la::dmatrix<std::complex<double>>& B__, double* eval__,
199 la::dmatrix<std::complex<double>>& Z__)
200{
201 return solve(matrix_size__, matrix_size__, A__, B__, eval__, Z__);
202}
203
204/// Solve a standard eigen-value problem for N lowest eigen-pairs.
205int Eigensolver_elpa::solve(ftn_int matrix_size__, ftn_int nev__, la::dmatrix<double>& A__, double* eval__, la::dmatrix<double>& Z__)
206{
207 PROFILE("Eigensolver_elpa|solve_std");
208
209 int nt = omp_get_max_threads();
210
211 if (A__.num_cols_local() != Z__.num_cols_local()) {
212 RTE_THROW("number of columns in A and Z don't match");
213 }
214
215 PROFILE_START("Eigensolver_elpa|solve_std|setup");
216
217 int error;
218 elpa_t handle;
219
220 handle = elpa_allocate(&error);
221 if (error != ELPA_OK) {
222 return 1;
223 }
224 setup_handler(handle, stage_, A__, matrix_size__, nev__);
225
226 PROFILE_STOP("Eigensolver_elpa|solve_std|setup");
227
228 auto& mph = get_memory_pool(sddk::memory_t::host);
229 auto w = mph.get_unique_ptr<double>(matrix_size__);
230
231 elpa_eigenvectors_a_h_a_d(handle, A__.at(sddk::memory_t::host), w.get(), Z__.at(sddk::memory_t::host), &error);
232
233 elpa_deallocate(handle, &error);
234
235 std::copy(w.get(), w.get() + nev__, eval__);
236 if (nt != omp_get_max_threads()) {
237 std::stringstream s;
238 s << "number of OMP threads was changed by elpa" << std::endl
239 << " initial number of threads : " << nt << std::endl
240 << " new number of threads : " << omp_get_max_threads();
241 RTE_THROW(s);
242 }
243 return 0;
244}
245
246/// Solve a standard eigen-value problem for N lowest eigen-pairs.
247int Eigensolver_elpa::solve(ftn_int matrix_size__, ftn_int nev__, la::dmatrix<std::complex<double>>& A__, double* eval__,
248 la::dmatrix<std::complex<double>>& Z__)
249{
250 PROFILE("Eigensolver_elpa|solve_std");
251
252 int nt = omp_get_max_threads();
253
254 if (A__.num_cols_local() != Z__.num_cols_local()) {
255 RTE_THROW("number of columns in A and Z don't match");
256 }
257
258 PROFILE_START("Eigensolver_elpa|solve_std|setup");
259
260 int error;
261 elpa_t handle;
262
263 handle = elpa_allocate(&error);
264 if (error != ELPA_OK) {
265 return 1;
266 }
267 setup_handler(handle, stage_, A__, matrix_size__, nev__);
268
269 PROFILE_STOP("Eigensolver_elpa|solve_std|setup");
270
271 auto& mph = get_memory_pool(sddk::memory_t::host);
272 auto w = mph.get_unique_ptr<double>(matrix_size__);
273
274 auto A_ptr = A__.size_local() ? A__.at(sddk::memory_t::host) : nullptr;
275 auto Z_ptr = Z__.size_local() ? Z__.at(sddk::memory_t::host) : nullptr;
276 elpa_eigenvectors_a_h_a_dc(handle, A_ptr, w.get(), Z_ptr, &error);
277
278 elpa_deallocate(handle, &error);
279
280 std::copy(w.get(), w.get() + nev__, eval__);
281
282 if (nt != omp_get_max_threads()) {
283 std::stringstream s;
284 s << "number of OMP threads was changed by elpa" << std::endl
285 << " initial number of threads : " << nt << std::endl
286 << " new number of threads : " << omp_get_max_threads();
287 RTE_THROW(s);
288 }
289
290 return 0;
291}
292
293/// Solve a standard eigen-value problem for all eigen-pairs.
294int Eigensolver_elpa::solve(ftn_int matrix_size__, la::dmatrix<double>& A__, double* eval__, la::dmatrix<double>& Z__)
295{
296 return solve(matrix_size__, matrix_size__, A__, eval__, Z__);
297}
298
299/// Solve a standard eigen-value problem for all eigen-pairs.
300int Eigensolver_elpa::solve(ftn_int matrix_size__, la::dmatrix<std::complex<double>>& A__, double* eval__, la::dmatrix<std::complex<double>>& Z__)
301{
302 return solve(matrix_size__, matrix_size__, A__, eval__, Z__);
303}
304
305#endif
306
307#if defined(SIRIUS_DLAF)
308
310{
311 const char* pika_argv[] = {"sirius", "--pika:print-bind"};
312 const char* dlaf_argv[] = {"sirius"};
313 dlaf_initialize(2, pika_argv, 1, dlaf_argv);
314}
315
316void Eigensolver_dlaf::finalize()
317{
318 dlaf_finalize();
319}
320
321#endif
322
323}
324
325}
Distributed matrix.
Definition: dmatrix.hpp:56
int num_cols_local() const
Local number of columns.
Definition: dmatrix.hpp:174
Contains definition and implementation of various eigenvalue solver interfaces.
memory_t
Memory types where the code can store data.
Definition: memory.hpp:71
@ error
throw a parse_error exception in case of a tag
int num_devices()
Get the number of devices.
Definition: acc.cpp:32
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
ev_solver_t
Type of eigen-value solver.
Definition: eigensolver.hpp:37
Namespace of the SIRIUS library.
Definition: sirius.f90:5
void initialize(bool call_mpi_init__=true)
Initialize the library.
Definition: sirius.hpp:82