MPI-SCATCI 2.0
An MPI version of SCATCI
Loading...
Searching...
No Matches
ELPADiagonalizer_module.f90
Go to the documentation of this file.
1! Copyright 2019
2!
3! For a comprehensive list of the developers that contributed to these codes
4! see the UK-AMOR website.
5!
6! This file is part of UKRmol-in (UKRmol+ suite).
7!
8! UKRmol-in is free software: you can redistribute it and/or modify
9! it under the terms of the GNU General Public License as published by
10! the Free Software Foundation, either version 3 of the License, or
11! (at your option) any later version.
12!
13! UKRmol-in is distributed in the hope that it will be useful,
14! but WITHOUT ANY WARRANTY; without even the implied warranty of
15! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16! GNU General Public License for more details.
17!
18! You should have received a copy of the GNU General Public License
19! along with UKRmol-in (in source/COPYING). Alternatively, you can also visit
20! <https://www.gnu.org/licenses/>.
21
22!> \brief Diagonalizer type using ELPA backend
23!> \authors J Benda
24!> \date 2019
25!>
26!> This module will be built only if ELPA (and ScaLAPACK) is available.
27!>
28module elpadiagonalizer_module
29
30 use diagonalizer_module, only: basediagonalizer
31 use baseintegral_module, only: baseintegral
32 use blas_lapack_gbl, only: blasint
33 use const_gbl, only: stdout
34 use mpi_gbl, only: mpi_xermsg, nprocs, myrank
35 use options_module, only: options
36 use parallelization_module, only: grid => process_grid
37 use precisn_gbl, only: wp
38 use elpamatrix_module, only: elpamatrix
39 use scalapackdiagonalizer_module, only: scalapackdiagonalizer
40 use scalapackmatrix_module, only: scalapackmatrix
41
42 use iso_c_binding, only: c_int
43 use elpa, only: elpa_t, elpa_allocate, elpa_deallocate, elpa_init, elpa_uninit, elpa_ok, elpa_solver_2stage
44
45 implicit none
46
47 integer, parameter :: elpaint = c_int
48
49 !> \brief Diagonalizer class
50 !> \authors J Benda
51 !> \date 2019
52 !>
53 !> ELPA diagonalizer class is based on SCALAPACKDiagonalizer and shares with its
54 !> parent class everything (including processing of solutions) except the very backend
55 !> used for the symmetric matrix diagonalization (subroutine diagonalize_backend).
56 !>
57 type, extends(scalapackdiagonalizer) :: elpadiagonalizer
58 contains
59 procedure, public :: diagonalize_backend => diagonalize_backend_elpa
60 end type elpadiagonalizer
61
62contains
63
64 !> \brief Initialize the ELPA library
65 !> \authors J Benda
66 !> \date 2019
67 !>
68 !> Set upt the ELPA library for use. This needs to be called once at the beginning of the
69 !> program. Initialization of the library selects a specific version of the API to use
70 !> when communicating with the library. Currently, the API of version 20181112 is used.
71 !>
72 subroutine initialize_elpa
73
74 integer(elpaint), parameter :: elpa_api = 20181112
75 integer(elpaint) :: success
76
77 success = elpa_init(elpa_api)
78 call elpa_assert('initialize_elpa', 'ELPA API version not supported', success)
79
80 end subroutine initialize_elpa
81
82
83 !> \brief Diagonalization kernel
84 !> \authors J Benda
85 !> \date 2019
86 !>
87 !> Perform the diagonalization of a symmetric cyclically block-distributed ScaLAPACK matrix.
88 !> Use the ELPA library. It is assumed that the library has been initialized prior to this
89 !> call. The eigenvectors will be stored in `z_mat`, eigenvalues in `w`, both of which will
90 !> be allocated by this subroutine.
91 !>
92 subroutine diagonalize_backend_elpa (this, matrix_elements, num_eigenpair, z_mat, w, all_procs, option, integrals)
93
94 class(elpadiagonalizer) :: this
95 class(scalapackmatrix), intent(in) :: matrix_elements
96 class(baseintegral), intent(in) :: integrals
97 type(options), intent(in) :: option
98 integer, intent(in) :: num_eigenpair
99 logical, intent(in) :: all_procs
100 real(wp), allocatable, intent(inout) :: z_mat(:,:), w(:)
101
102 integer :: ierr
103 integer(elpaint) :: success, nb, loc_r, loc_c, mat_dimen, myrow, mycol, nev, comm
104 class(elpa_t), pointer :: elpa
105
106 write (stdout, "('Diagonalization will be done with ELPA')")
107
108 comm = grid % gcomm
109 myrow = grid % mygrow
110 mycol = grid % mygcol
111 nev = num_eigenpair
112
113 mat_dimen = matrix_elements % get_matrix_size()
114 loc_r = matrix_elements % local_row_dimen
115 loc_c = matrix_elements % local_col_dimen
116 nb = matrix_elements % scal_block_size
117
118 ! allocate the eigenvectors
119 allocate(z_mat(loc_r, loc_c), w(mat_dimen), stat = ierr)
120 if (ierr /= 0) then
121 call mpi_xermsg('ELPADiagonalizer_module', 'diagonalize_backend_ELPA', 'Memory allocation error.', ierr, 1)
122 end if
123
124 ! create the ELPA object
125 elpa => elpa_allocate(success)
126 call elpa_assert('diagonalize_backend_ELPA', 'Failed to create ELPA object.', success)
127
128 ! set matrix-related ELPA parameters
129 call elpa % set('na', mat_dimen, success)
130 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "na" for ELPA.', success)
131 call elpa % set('nev', mat_dimen, success)
132 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "nev" for ELPA.', success)
133 call elpa % set('local_nrows', loc_r, success)
134 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "local_nrows" for ELPA.', success)
135 call elpa % set('local_ncols', loc_c, success)
136 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "local_ncols" for ELPA.', success)
137 call elpa % set('nblk', nb, success)
138 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "nblk" for ELPA.', success)
139 call elpa % set('mpi_comm_parent', comm, success)
140 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "mpi_comm_parent" for ELPA.', success)
141 call elpa % set('process_row', myrow, success)
142 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "process_row" for ELPA.', success)
143 call elpa % set('process_col', mycol, success)
144 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set "process_col" for ELPA.', success)
145
146 ! finalize the setup
147 success = elpa % setup()
148 call elpa_assert('diagonalize_backend_ELPA', 'Failed to set up the ELPA object.', success)
149
150 ! use 2-stage solver by default (i.e. when not given in environment variable)
151 call get_environment_variable('ELPA_DEFAULT_solver', status = ierr)
152 if (ierr > 0) then
153 ! environment variable ELPA_DEFAULT_solver does not exist (= 1) or environment variables are not supported at all (= 2)
154 call elpa % set("solver", elpa_solver_2stage, success)
155 call elpa_assert('diagonalize_backend_ELPA', 'Failed to switch ELPA to the 2-stage solver.', success)
156 end if
157
158 ! run the solver
159 call elpa % eigenvectors(matrix_elements % a_local_matrix, w, z_mat, success)
160 call elpa_assert('diagonalize_backend_ELPA', 'Diagonalization using ELPA failed.', success)
161
162 ! free the memory, possible getting ready for another diagonalization
163 call elpa_deallocate(elpa, success)
164 call elpa_assert('diagonalize_backend_ELPA', 'Failed to deallocate the ELPA object.', success)
165
166 end subroutine diagonalize_backend_elpa
167
168
169 !> \brief Check ELPA error code
170 !> \authors J Benda
171 !> \date 2019
172 !>
173 !> Verify that the given ELPA error code is equal to ELPA_OK. If not, print the given error message
174 !> and terminate the program.
175 !>
176 subroutine elpa_assert (sub, msg, err)
177
178 character(len=*), intent(in) :: sub, msg
179 integer(elpaint), intent(in) :: err
180
181 if (err /= elpa_ok) then
182 call mpi_xermsg('ELPADiagonalizer_module', sub, msg, int(err), 1)
183 end if
184
185 end subroutine elpa_assert
186
187end module elpadiagonalizer_module