2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2012,2013,2014,2015,2016,2017, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
39 #include "eigensolver.h"
41 #include "gromacs/linearalgebra/sparsematrix.h"
42 #include "gromacs/utility/fatalerror.h"
43 #include "gromacs/utility/real.h"
44 #include "gromacs/utility/smalloc.h"
46 #include "gmx_arpack.h"
47 #include "gmx_lapack.h"
76 /* Make jobz point to the character "V" if eigenvectors
77 * should be calculated, otherwise "N" (only eigenvalues).
79 jobz
= (eigenvectors
!= nullptr) ? "V" : "N";
81 /* allocate lapack stuff */
85 /* First time we ask the routine how much workspace it needs */
90 /* Convert indices to fortran standard */
94 /* Call LAPACK routine using fortran interface. Note that we use upper storage,
95 * but this corresponds to lower storage ("L") in Fortran.
98 F77_FUNC(dsyevr
, DSYEVR
) (jobz
, "I", "L", &n
, a
, &n
, &vl
, &vu
, &index_lower
, &index_upper
,
99 &abstol
, &m
, eigenvalues
, eigenvectors
, &n
,
100 isuppz
, &w0
, &lwork
, &iw0
, &liwork
, &info
);
102 F77_FUNC(ssyevr
, SSYEVR
) (jobz
, "I", "L", &n
, a
, &n
, &vl
, &vu
, &index_lower
, &index_upper
,
103 &abstol
, &m
, eigenvalues
, eigenvectors
, &n
,
104 isuppz
, &w0
, &lwork
, &iw0
, &liwork
, &info
);
110 gmx_fatal(FARGS
, "Internal errror in LAPACK diagonalization.");
113 lwork
= static_cast<int>(w0
);
122 F77_FUNC(dsyevr
, DSYEVR
) (jobz
, "I", "L", &n
, a
, &n
, &vl
, &vu
, &index_lower
, &index_upper
,
123 &abstol
, &m
, eigenvalues
, eigenvectors
, &n
,
124 isuppz
, work
, &lwork
, iwork
, &liwork
, &info
);
126 F77_FUNC(ssyevr
, SSYEVR
) (jobz
, "I", "L", &n
, a
, &n
, &vl
, &vu
, &index_lower
, &index_upper
,
127 &abstol
, &m
, eigenvalues
, eigenvectors
, &n
,
128 isuppz
, work
, &lwork
, iwork
, &liwork
, &info
);
137 gmx_fatal(FARGS
, "Internal errror in LAPACK diagonalization.");
145 sparse_parallel_eigensolver(gmx_sparsematrix_t
* A
,
159 int ido
, info
, lworkl
, i
, ncv
, dovec
;
165 MPI_Comm_size( MPI_COMM_WORLD
, &nnodes
);
166 MPI_Comm_rank( MPI_COMM_WORLD
, &rank
);
168 if (eigenvectors
!= NULL
)
185 for (i
= 0; i
< 11; i
++)
187 iparam
[i
] = ipntr
[i
] = 0;
190 iparam
[0] = 1; /* Don't use explicit shifts */
191 iparam
[2] = maxiter
; /* Max number of iterations */
192 iparam
[6] = 1; /* Standard symmetric eigenproblem */
194 lworkl
= ncv
*(8+ncv
);
196 snew(workd
, (3*n
+4));
201 /* Use machine tolerance - roughly 1e-16 in double precision */
205 fprintf(stderr
, "Calculation Ritz values and Lanczos vectors, max %d iterations...\n", maxiter
);
211 F77_FUNC(pdsaupd
, PDSAUPD
) (&ido
, "I", &n
, "SA", &neig
, &abstol
,
212 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
213 workd
, iwork
, workl
, &lworkl
, &info
);
215 F77_FUNC(pssaupd
, PSSAUPD
) (&ido
, "I", &n
, "SA", &neig
, &abstol
,
216 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
217 workd
, iwork
, workl
, &lworkl
, &info
);
219 if (ido
== -1 || ido
== 1)
221 gmx_sparsematrix_vector_multiply(A
, workd
+ipntr
[0]-1, workd
+ipntr
[1]-1);
224 fprintf(stderr
, "\rIteration %4d: %3d out of %3d Ritz values converged.", iter
++, iparam
[4], neig
);
227 while (info
== 0 && (ido
== -1 || ido
== 1));
229 fprintf(stderr
, "\n");
233 "Maximum number of iterations (%d) reached in Arnoldi\n"
234 "diagonalization, but only %d of %d eigenvectors converged.\n",
235 maxiter
, iparam
[4], neig
);
239 gmx_fatal(FARGS
, "Unspecified error from Arnoldi diagonalization:%d\n", info
);
243 /* Extract eigenvalues and vectors from data */
244 fprintf(stderr
, "Calculating eigenvalues and eigenvectors...\n");
247 F77_FUNC(pdseupd
, PDSEUPD
) (&dovec
, "A", select
, eigenvalues
, eigenvectors
,
248 &n
, NULL
, "I", &n
, "SA", &neig
, &abstol
,
249 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
250 workd
, workl
, &lworkl
, &info
);
252 F77_FUNC(psseupd
, PSSEUPD
) (&dovec
, "A", select
, eigenvalues
, eigenvectors
,
253 &n
, NULL
, "I", &n
, "SA", &neig
, &abstol
,
254 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
255 workd
, workl
, &lworkl
, &info
);
268 sparse_eigensolver(gmx_sparsematrix_t
* A
,
282 int ido
, info
, lworkl
, i
, ncv
, dovec
;
288 MPI_Comm_size( MPI_COMM_WORLD
, &n
);
291 sparse_parallel_eigensolver(A
, neig
, eigenvalues
, eigenvectors
, maxiter
);
296 if (eigenvectors
!= nullptr)
313 for (i
= 0; i
< 11; i
++)
315 iparam
[i
] = ipntr
[i
] = 0;
318 iparam
[0] = 1; /* Don't use explicit shifts */
319 iparam
[2] = maxiter
; /* Max number of iterations */
320 iparam
[6] = 1; /* Standard symmetric eigenproblem */
322 lworkl
= ncv
*(8+ncv
);
324 snew(workd
, (3*n
+4));
329 /* Use machine tolerance - roughly 1e-16 in double precision */
333 fprintf(stderr
, "Calculation Ritz values and Lanczos vectors, max %d iterations...\n", maxiter
);
339 F77_FUNC(dsaupd
, DSAUPD
) (&ido
, "I", &n
, "SA", &neig
, &abstol
,
340 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
341 workd
, iwork
, workl
, &lworkl
, &info
);
343 F77_FUNC(ssaupd
, SSAUPD
) (&ido
, "I", &n
, "SA", &neig
, &abstol
,
344 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
345 workd
, iwork
, workl
, &lworkl
, &info
);
347 if (ido
== -1 || ido
== 1)
349 gmx_sparsematrix_vector_multiply(A
, workd
+ipntr
[0]-1, workd
+ipntr
[1]-1);
352 fprintf(stderr
, "\rIteration %4d: %3d out of %3d Ritz values converged.", iter
++, iparam
[4], neig
);
355 while (info
== 0 && (ido
== -1 || ido
== 1));
357 fprintf(stderr
, "\n");
361 "Maximum number of iterations (%d) reached in Arnoldi\n"
362 "diagonalization, but only %d of %d eigenvectors converged.\n",
363 maxiter
, iparam
[4], neig
);
367 gmx_fatal(FARGS
, "Unspecified error from Arnoldi diagonalization:%d\n", info
);
371 /* Extract eigenvalues and vectors from data */
372 fprintf(stderr
, "Calculating eigenvalues and eigenvectors...\n");
375 F77_FUNC(dseupd
, DSEUPD
) (&dovec
, "A", select
, eigenvalues
, eigenvectors
,
376 &n
, nullptr, "I", &n
, "SA", &neig
, &abstol
,
377 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
378 workd
, workl
, &lworkl
, &info
);
380 F77_FUNC(sseupd
, SSEUPD
) (&dovec
, "A", select
, eigenvalues
, eigenvectors
,
381 &n
, nullptr, "I", &n
, "SA", &neig
, &abstol
,
382 resid
, &ncv
, v
, &n
, iparam
, ipntr
,
383 workd
, workl
, &lworkl
, &info
);