Eigenvalue SoLvers for Petaflop-Applications (ELPA) 2025.01.002
Loading...
Searching...
No Matches
elpa_impl_math_generalized_template.F90
Go to the documentation of this file.
1!
2! Copyright 2017, L. Hüdepohl and A. Marek, MPCDF
3!
4! This file is part of ELPA.
5!
6! The ELPA library was originally created by the ELPA consortium,
7! consisting of the following organizations:
8!
9! - Max Planck Computing and Data Facility (MPCDF), formerly known as
10! Rechenzentrum Garching der Max-Planck-Gesellschaft (RZG),
11! - Bergische Universität Wuppertal, Lehrstuhl für angewandte
12! Informatik,
13! - Technische Universität München, Lehrstuhl für Informatik mit
14! Schwerpunkt Wissenschaftliches Rechnen ,
15! - Fritz-Haber-Institut, Berlin, Abt. Theorie,
16! - Max-Plack-Institut für Mathematik in den Naturwissenschaften,
17! Leipzig, Abt. Komplexe Strukutren in Biologie und Kognition,
18! and
19! - IBM Deutschland GmbH
20!
21! This particular source code file contains additions, changes and
22! enhancements authored by Intel Corporation which is not part of
23! the ELPA consortium.
24!
25! More information can be found here:
26! http://elpa.mpcdf.mpg.de/
27!
28! ELPA is free software: you can redistribute it and/or modify
29! it under the terms of the version 3 of the license of the
30! GNU Lesser General Public License as published by the Free
31! Software Foundation.
32!
33! ELPA is distributed in the hope that it will be useful,
34! but WITHOUT ANY WARRANTY; without even the implied warranty of
35! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36! GNU Lesser General Public License for more details.
37!
38! You should have received a copy of the GNU Lesser General Public License
39! along with ELPA. If not, see <http://www.gnu.org/licenses/>
40!
41! ELPA reflects a substantial effort on the part of the original
42! ELPA consortium, and we ask you to respect the spirit of the
43! license that we chose: i.e., please contribute any changes you
44! may have back to the original ELPA library distribution, and keep
45! any derivatives of ELPA under the same license that we chose for
46! the original distribution, the GNU Lesser General Public License.
47
48!> \brief elpa_generalized_eigenvectors_a_h_a: class method to solve the eigenvalue problem, using host arrays
49!>
50!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
51!> blocksize, the number of eigenvectors
52!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
53!> with the class method "setup"
54!>
55!> It is possible to change the behaviour of the method by setting tunable parameters with the
56!> class method "set"
57!>
58!> Parameters
59!>
60!> \param a Distributed matrix for which eigenvalues are to be computed.
61!> Distribution is like in Scalapack.
62!> The full matrix must be set (not only one half like in scalapack).
63!> Destroyed on exit (upper and lower half).
64!>
65!> \param b Distributed matrix, part of the generalized eigenvector problem, or the
66!> product of a previous call to this function (see is_already_decomposed).
67!> Distribution is like in Scalapack.
68!> If is_already_decomposed is false, on exit replaced by the decomposition
69!>
70!> \param ev On output: eigenvalues of a, every processor gets the complete set
71!>
72!> \param q On output: Eigenvectors of a
73!> Distribution is like in Scalapack.
74!> Must be always dimensioned to the full size (corresponding to (na,na))
75!> even if only a part of the eigenvalues is needed.
76!>
77!> \param is_already_decomposed has to be set to .false. for the first call with a given b and .true. for
78!> each subsequent call with the same b, since b then already contains
79!> decomposition and thus the decomposing step is skipped
80!>
81!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
82subroutine elpa_generalized_eigenvectors_a_h_a_&
83 &elpa_impl_suffix&
84 & (self, a, b, ev, q, is_already_decomposed, error)
85 use elpa1_impl
86 use elpa2_impl
87 use elpa_utilities, only : error_unit
88 use, intrinsic :: iso_c_binding
89 class(elpa_impl_t) :: self
90
91#ifdef USE_ASSUMED_SIZE
92 math_datatype(kind=c_datatype_kind) :: a(self%local_nrows, *), b(self%local_nrows, *), q(self%local_nrows, *)
93#else
94 math_datatype(kind=c_datatype_kind) :: a(self%local_nrows, self%local_ncols), b(self%local_nrows, self%local_ncols), &
95 q(self%local_nrows, self%local_ncols)
96#endif
97 real(kind=c_real_datatype) :: ev(self%na)
98
99 logical :: is_already_decomposed
100 integer, optional :: error
101 integer :: error_l
102
103 logical :: success_l
104 integer(kind=c_int) :: solver
105
106 error_l = -10
107 success_l = .false.
108
109#if defined(INCLUDE_ROUTINES)
110 call self%elpa_transform_generalized_a_h_a_&
111 &elpa_impl_suffix&
112 & (a, b, q, is_already_decomposed, error_l)
113#endif
114
115 if (present(error)) then
116 error = error_l
117 else if (error_l .ne. elpa_ok) then
118 write(error_unit,'(a)') "ELPA: Error in elpa_transform_generalized_a_h_a() and you did not check for errors!"
119 endif
120
121 call self%get("solver", solver,error_l)
122 if (solver .eq. elpa_solver_1stage) then
123#if defined(INCLUDE_ROUTINES)
124 success_l = elpa_solve_evp_&
125 &math_datatype&
126 &_1stage_a_h_a_&
127 &precision&
128 &_impl(self, a, ev, q)
129#endif
130 else if (solver .eq. elpa_solver_2stage) then
131#if defined(INCLUDE_ROUTINES)
132 success_l = elpa_solve_evp_&
133 &math_datatype&
134 &_2stage_a_h_a_&
135 &precision&
136 &_impl(self, a, ev, q)
137#endif
138 else ! (solver .eq. ELPA_SOLVER_..STAGE)
139 write(error_unit,'(a)') "Unknown solver: Aborting!"
140#ifdef USE_FORTRAN2008
141 if (present(error)) then
142 error = elpa_error
143 return
144 else
145 return
146 endif
147#else
148 error = elpa_error
149 return
150#endif
151 endif ! (solver .eq. ELPA_SOLVER_..STAGE)
152
153 if (present(error)) then
154 if (success_l) then
155 error = elpa_ok
156 else
157 error = elpa_error
158 endif
159 else if (.not. success_l) then
160 write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
161 endif
162
163#if defined(INCLUDE_ROUTINES)
164 call self%elpa_transform_back_generalized_a_h_a_&
165 &elpa_impl_suffix&
166 & (b, q, a, error_l)
167#endif
168
169 if (present(error)) then
170 error = error_l
171 else if (error_l .ne. elpa_ok) then
172 write(error_unit,'(a)') "ELPA: Error in transform_back_generalized_a_h_a() and you did not check for errors!"
173 endif
174end subroutine
175
176 !c> // /src/elpa_impl_math_generalized_template.F90
177
178#ifdef REALCASE
179#ifdef DOUBLE_PRECISION_REAL
180 !c> void elpa_generalized_eigenvectors_a_h_a_d(elpa_t handle, double *a, double *b, double *ev, double *q,
181 !c> int is_already_decomposed, int *error);
182#endif
183#ifdef SINGLE_PRECISION_REAL
184 !c> void elpa_generalized_eigenvectors_a_h_a_f(elpa_t handle, float *a, float *b, float *ev, float *q,
185 !c> int is_already_decomposed, int *error);
186#endif
187#endif
188#ifdef COMPLEXCASE
189#ifdef DOUBLE_PRECISION_COMPLEX
190 !c> void elpa_generalized_eigenvectors_a_h_a_dc(elpa_t handle, double_complex *a, double_complex *b, double *ev, double_complex *q,
191 !c> int is_already_decomposed, int *error);
192#endif
193#ifdef SINGLE_PRECISION_COMPLEX
194 !c> void elpa_generalized_eigenvectors_a_h_a_fc(elpa_t handle, float_complex *a, float_complex *b, float *ev, float_complex *q,
195 !c> int is_already_decomposed, int *error);
196#endif
197#endif
198 subroutine elpa_generalized_eigenvectors_a_h_a_&
199 &elpa_impl_suffix&
200 &_c(handle, a_p, b_p, ev_p, q_p, is_already_decomposed, error) &
201#ifdef REALCASE
202#ifdef DOUBLE_PRECISION_REAL
203 bind(C, name="elpa_generalized_eigenvectors_a_h_a_d")
204#endif
205#ifdef SINGLE_PRECISION_REAL
206 bind(C, name="elpa_generalized_eigenvectors_a_h_a_f")
207#endif
208#endif
209#ifdef COMPLEXCASE
210#ifdef DOUBLE_PRECISION_COMPLEX
211 bind(C, name="elpa_generalized_eigenvectors_a_h_a_dc")
212#endif
213#ifdef SINGLE_PRECISION_COMPLEX
214 bind(C, name="elpa_generalized_eigenvectors_a_h_a_fc")
215#endif
216#endif
217 type(c_ptr), intent(in), value :: handle, a_p, b_p, ev_p, q_p
218 integer(kind=c_int), intent(in), value :: is_already_decomposed
219#ifdef USE_FORTRAN2008
220 integer(kind=c_int), optional, intent(in) :: error
221#else
222 integer(kind=c_int), intent(in) :: error
223#endif
224 math_datatype(kind=c_datatype_kind), pointer :: a(:, :), b(:, :), q(:, :)
225 real(kind=c_real_datatype), pointer :: ev(:)
226 logical :: is_already_decomposed_fortran
227 type(elpa_impl_t), pointer :: self
228
229 call c_f_pointer(handle, self)
230 call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
231 call c_f_pointer(b_p, b, [self%local_nrows, self%local_ncols])
232 call c_f_pointer(ev_p, ev, [self%na])
233 call c_f_pointer(q_p, q, [self%local_nrows, self%local_ncols])
234 if(is_already_decomposed .eq. 0) then
235 is_already_decomposed_fortran = .false.
236 else
237 is_already_decomposed_fortran = .true.
238 end if
239
240 call elpa_generalized_eigenvectors_a_h_a_&
241 &elpa_impl_suffix&
242 & (self, a, b, ev, q, is_already_decomposed_fortran, error)
243 end subroutine
244
245!__________________________________________________________________________________________________
246
247!> \brief elpa_generalized_eigenvectors_d_ptr: class method to solve the eigenvalue problem, using device pointers
248!>
249!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
250!> blocksize, the number of eigenvectors
251!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
252!> with the class method "setup"
253!>
254!> It is possible to change the behaviour of the method by setting tunable parameters with the
255!> class method "set"
256!>
257!> Parameters
258!>
259!> \param a Distributed matrix for which eigenvalues are to be computed.
260!> Distribution is like in Scalapack.
261!> The full matrix must be set (not only one half like in scalapack).
262!> Destroyed on exit (upper and lower half).
263!>
264!> \param b Distributed matrix, part of the generalized eigenvector problem, or the
265!> product of a previous call to this function (see is_already_decomposed).
266!> Distribution is like in Scalapack.
267!> If is_already_decomposed is false, on exit replaced by the decomposition
268!>
269!> \param ev On output: eigenvalues of a, every processor gets the complete set
270!>
271!> \param q On output: Eigenvectors of a
272!> Distribution is like in Scalapack.
273!> Must be always dimensioned to the full size (corresponding to (na,na))
274!> even if only a part of the eigenvalues is needed.
275!>
276!> \param is_already_decomposed has to be set to .false. for the first call with a given b and .true. for
277!> each subsequent call with the same b, since b then already contains
278!> decomposition and thus the decomposing step is skipped
279!>
280!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
281subroutine elpa_generalized_eigenvectors_d_ptr_&
282 &elpa_impl_suffix&
283 & (self, adev, bdev, evdev, qdev, is_already_decomposed, error)
284 use elpa1_impl
285 use elpa2_impl
286 use elpa_utilities, only : error_unit
287 use elpa_gpu
288 use elpa_gpu_util
289 use mod_query_gpu_usage
290 use mod_check_for_gpu
291 use, intrinsic :: iso_c_binding
292 class(elpa_impl_t) :: self
293
294 type(c_ptr) :: aDev, bDev, evDev, qDev
295
296 logical :: is_already_decomposed
297 integer, optional :: error
298 integer :: error_l
299
300 logical :: success_l, wantDebug
301 integer(kind=c_int) :: solver, debug
302
303 logical :: useGPU, successGPU
304 integer(kind=c_int) :: myid, numberOfGPUDevices
305
306 error_l = -10
307 success_l = .false.
308 if (present(error)) then
309 error = error_l
310 endif
311
312 call self%get("debug", debug, error_l)
313 if (error_l .ne. elpa_ok) then
314 write(error_unit,*) "elpa_generalized_eigenvectors_d_ptr: Problem getting option for debug settings. Aborting..."
315 endif
316 wantdebug = (debug == 1)
317
318! PETERDEBUG: new: check whether gpu keywords are set and check number of available GPUs
319 usegpu = .false.
320#if defined(WITH_NVIDIA_GPU_VERSION) || defined(WITH_AMD_GPU_VERSION) || defined(WITH_OPENMP_OFFLOAD_GPU_VERSION) || defined(WITH_SYCL_GPU_VERSION)
321 if (.not.(query_gpu_usage(self, "elpa_generalized_eigenvectors_d_ptr", usegpu))) then
322 write(error_unit,*) "elpa_generalized_eigenvectors_d_ptr: Problem getting options for GPU. Aborting..."
323 return
324 endif
325
326 if (usegpu) then
327 myid = self%mpi_setup%myRank_comm_parent
328 call self%timer%start("check_for_gpu")
329
330 if (check_for_gpu(self, myid, numberofgpudevices, wantdebug=wantdebug)) then
331 call set_gpu_parameters()
332 else
333 write(error_unit, *) "GPUs are requested but not detected! Aborting..."
334 call self%timer%stop("check_for_gpu")
335 return
336 endif
337 call self%timer%stop("check_for_gpu")
338 endif ! useGPU
339#endif
340
341#if defined(INCLUDE_ROUTINES)
342 call self%elpa_transform_generalized_d_ptr_&
343 &elpa_impl_suffix&
344 & (adev, bdev, qdev, is_already_decomposed, error_l)
345#endif
346
347 if (present(error)) then
348 error = error_l
349 else if (error_l .ne. elpa_ok) then
350 write(error_unit,'(a)') "ELPA: Error in transform_generalized() and you did not check for errors!"
351 endif
352
353 call self%get("solver", solver,error_l)
354 if (solver .eq. elpa_solver_1stage) then
355#if defined(INCLUDE_ROUTINES)
356 success_l = elpa_solve_evp_&
357 &math_datatype&
358 &_1stage_d_ptr_&
359 &precision&
360 &_impl(self, adev, evdev, qdev)
361#endif
362 else if (solver .eq. elpa_solver_2stage) then
363#if defined(INCLUDE_ROUTINES)
364 success_l = elpa_solve_evp_&
365 &math_datatype&
366 &_2stage_d_ptr_&
367 &precision&
368 &_impl(self, adev, evdev, qdev)
369#endif
370 else ! (solver .eq. ELPA_SOLVER_..STAGE)
371 write(error_unit,'(a)') "Unknown solver: Aborting!"
372#ifdef USE_FORTRAN2008
373 if (present(error)) then
374 error = elpa_error
375 return
376 else
377 return
378 endif
379#else
380 error = elpa_error
381 return
382#endif
383 endif ! (solver .eq. ELPA_SOLVER_..STAGE)
384
385 if (present(error)) then
386 if (success_l) then
387 error = elpa_ok
388 else
389 error = elpa_error
390 endif
391 else if (.not. success_l) then
392 write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
393 endif
394
395#if defined(INCLUDE_ROUTINES)
396 call self%elpa_transform_back_generalized_d_ptr_&
397 &elpa_impl_suffix&
398 & (bdev, qdev, adev, error_l)
399#endif
400
401 if (present(error)) then
402 error = error_l
403 else if (error_l .ne. elpa_ok) then
404 write(error_unit,'(a)') "ELPA: Error in transform_back_generalized_d_ptr() and you did not check for errors!"
405 endif
406end subroutine
407
408#ifdef REALCASE
409#ifdef DOUBLE_PRECISION_REAL
410 !c> void elpa_generalized_eigenvectors_d_ptr_d(elpa_t handle, double *a, double *b, double *ev, double *q,
411 !c> int is_already_decomposed, int *error);
412#endif
413#ifdef SINGLE_PRECISION_REAL
414 !c> void elpa_generalized_eigenvectors_d_ptr_f(elpa_t handle, float *a, float *b, float *ev, float *q,
415 !c> int is_already_decomposed, int *error);
416#endif
417#endif
418#ifdef COMPLEXCASE
419#ifdef DOUBLE_PRECISION_COMPLEX
420 !c> void elpa_generalized_eigenvectors_d_ptr_dc(elpa_t handle, double_complex *a, double_complex *b, double *ev, double_complex *q,
421 !c> int is_already_decomposed, int *error);
422#endif
423#ifdef SINGLE_PRECISION_COMPLEX
424 !c> void elpa_generalized_eigenvectors_d_ptr_fc(elpa_t handle, float_complex *a, float_complex *b, float *ev, float_complex *q,
425 !c> int is_already_decomposed, int *error);
426#endif
427#endif
428 subroutine elpa_generalized_eigenvectors_d_ptr_&
429 &elpa_impl_suffix&
430 &_c(handle, a_p, b_p, ev_p, q_p, is_already_decomposed, error) &
431#ifdef REALCASE
432#ifdef DOUBLE_PRECISION_REAL
433 bind(C, name="elpa_generalized_eigenvectors_d_ptr_d")
434#endif
435#ifdef SINGLE_PRECISION_REAL
436 bind(C, name="elpa_generalized_eigenvectors_d_ptr_f")
437#endif
438#endif
439#ifdef COMPLEXCASE
440#ifdef DOUBLE_PRECISION_COMPLEX
441 bind(C, name="elpa_generalized_eigenvectors_d_ptr_dc")
442#endif
443#ifdef SINGLE_PRECISION_COMPLEX
444 bind(C, name="elpa_generalized_eigenvectors_d_ptr_fc")
445#endif
446#endif
447 type(c_ptr), intent(in), value :: handle, a_p, b_p, ev_p, q_p
448 integer(kind=c_int), intent(in), value :: is_already_decomposed
449#ifdef USE_FORTRAN2008
450 integer(kind=c_int), optional, intent(in) :: error
451#else
452 integer(kind=c_int), intent(in) :: error
453#endif
454 !MATH_DATATYPE(kind=C_DATATYPE_KIND), pointer :: a(:, :), b(:, :), q(:, :)
455 !real(kind=C_REAL_DATATYPE), pointer :: ev(:)
456 logical :: is_already_decomposed_fortran
457 type(elpa_impl_t), pointer :: self
458
459 call c_f_pointer(handle, self)
460 !call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
461 !call c_f_pointer(b_p, b, [self%local_nrows, self%local_ncols])
462 !call c_f_pointer(ev_p, ev, [self%na])
463 !call c_f_pointer(q_p, q, [self%local_nrows, self%local_ncols])
464 if(is_already_decomposed .eq. 0) then
465 is_already_decomposed_fortran = .false.
466 else
467 is_already_decomposed_fortran = .true.
468 end if
469
470 call elpa_generalized_eigenvectors_d_ptr_&
471 &elpa_impl_suffix&
472 & (self, a_p, b_p, ev_p, q_p, is_already_decomposed_fortran, error)
473 end subroutine
474
475!__________________________________________________________________________________________________
476
477 !> \brief elpa_generalized_eigenvalues_a_h_a: class method to solve the eigenvalue problem, using host arrays
478 !>
479 !> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
480 !> blocksize, the number of eigenvectors
481 !> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
482 !> with the class method "setup"
483 !>
484 !> It is possible to change the behaviour of the method by setting tunable parameters with the
485 !> class method "set"
486 !>
487 !> Parameters
488 !>
489 !> \param a Distributed matrix for which eigenvalues are to be computed.
490 !> Distribution is like in Scalapack.
491 !> The full matrix must be set (not only one half like in scalapack).
492 !> Destroyed on exit (upper and lower half).
493 !>
494 !> \param b Distributed matrix, part of the generalized eigenvector problem, or the
495 !> product of a previous call to this function (see is_already_decomposed).
496 !> Distribution is like in Scalapack.
497 !> If is_already_decomposed is false, on exit replaced by the decomposition
498 !>
499 !> \param ev On output: eigenvalues of a, every processor gets the complete set
500 !>
501 !> \param is_already_decomposed has to be set to .false. for the first call with a given b and .true. for
502 !> each subsequent call with the same b, since b then already contains
503 !> decomposition and thus the decomposing step is skipped
504 !>
505 !> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
506 subroutine elpa_generalized_eigenvalues_a_h_a_&
507 &elpa_impl_suffix&
508 & (self, a, b, ev, is_already_decomposed, error)
509 use elpa1_impl
510 use elpa2_impl
511 use elpa_utilities, only : error_unit, check_alloc, check_allocate_f
512
513 use, intrinsic :: iso_c_binding
514 class(elpa_impl_t) :: self
515
516#ifdef USE_ASSUMED_SIZE
517 math_datatype(kind=c_datatype_kind) :: a(self%local_nrows, *), b(self%local_nrows, *)
518#else
519 math_datatype(kind=c_datatype_kind) :: a(self%local_nrows, self%local_ncols), b(self%local_nrows, self%local_ncols)
520#endif
521 real(kind=c_real_datatype) :: ev(self%na)
522 logical :: is_already_decomposed
523
524 integer, optional :: error
525 integer :: error_l
526 integer(kind=c_int) :: solver
527 logical :: success_l
528
529 integer(kind=ik) :: istat
530 character(200) :: errorMessage
531 math_datatype(kind=c_datatype_kind), allocatable :: tmp(:,:)
532
533 error_l = -10
534 success_l = .false.
535
536 allocate(tmp(self%local_nrows, self%local_ncols), stat=istat, errmsg=errormessage)
537 check_allocate("elpa_generalized_eigenvalues_a_h_a: tmp", istat, errormessage)
538
539#if defined(INCLUDE_ROUTINES)
540 call self%elpa_transform_generalized_a_h_a_&
541 &elpa_impl_suffix&
542 & (a, b, tmp, is_already_decomposed, error_l)
543#endif
544 if (present(error)) then
545 error = error_l
546 else if (error_l .ne. elpa_ok) then
547 write(error_unit,'(a)') "ELPA: Error in transform_generalized() and you did not check for errors!"
548 endif
549
550 deallocate(tmp, stat=istat, errmsg=errormessage)
551 check_deallocate("elpa_generalized_eigenvalues_a_h_a: tmp", istat, errormessage)
552
553 call self%get("solver", solver,error_l)
554 if (solver .eq. elpa_solver_1stage) then
555#if defined(INCLUDE_ROUTINES)
556 success_l = elpa_solve_evp_&
557 &math_datatype&
558 &_1stage_a_h_a_&
559 &precision&
560 &_impl(self, a, ev)
561#endif
562 else if (solver .eq. elpa_solver_2stage) then
563#if defined(INCLUDE_ROUTINES)
564 success_l = elpa_solve_evp_&
565 &math_datatype&
566 &_2stage_a_h_a_&
567 &precision&
568 &_impl(self, a, ev)
569#endif
570 else
571 write(error_unit,'(a)') "Unknown solver: Aborting!"
572#ifdef USE_FORTRAN2008
573 if (present(error)) then
574 error = elpa_error
575 return
576 else
577 return
578 endif
579#else
580 error = elpa_error
581 return
582#endif
583 endif
584
585 if (present(error)) then
586 if (success_l) then
587 error = elpa_ok
588 else
589 error = elpa_error
590 endif
591 else if (.not. success_l) then
592 write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
593 endif
594
595 end subroutine
596
597#ifdef REALCASE
598#ifdef DOUBLE_PRECISION_REAL
599 !c> void elpa_generalized_eigenvalues_a_h_a_d(elpa_t handle, double *a, double *b, double *ev,
600 !c> int is_already_decomposed, int *error);
601#endif
602#ifdef SINGLE_PRECISION_REAL
603 !c> void elpa_generalized_eigenvalues_a_h_a_f(elpa_t handle, float *a, float *b, float *ev,
604 !c> int is_already_decomposed, int *error);
605#endif
606#endif
607#ifdef COMPLEXCASE
608#ifdef DOUBLE_PRECISION_COMPLEX
609 !c> void elpa_generalized_eigenvalues_a_h_a_dc(elpa_t handle, double_complex *a, double_complex *b, double *ev,
610 !c> int is_already_decomposed, int *error);
611#endif
612#ifdef SINGLE_PRECISION_COMPLEX
613 !c> void elpa_generalized_eigenvalues_a_h_a_fc(elpa_t handle, float_complex *a, float_complex *b, float *ev,
614 !c> int is_already_decomposed, int *error);
615#endif
616#endif
617 subroutine elpa_generalized_eigenvalues_a_h_a_&
618 &elpa_impl_suffix&
619 &_c(handle, a_p, b_p, ev_p, is_already_decomposed, error) &
620#ifdef REALCASE
621#ifdef DOUBLE_PRECISION_REAL
622 bind(C, name="elpa_generalized_eigenvalues_a_h_a_d")
623#endif
624#ifdef SINGLE_PRECISION_REAL
625 bind(C, name="elpa_generalized_eigenvalues_a_h_a_f")
626#endif
627#endif
628#ifdef COMPLEXCASE
629#ifdef DOUBLE_PRECISION_COMPLEX
630 bind(C, name="elpa_generalized_eigenvalues_a_h_a_dc")
631#endif
632#ifdef SINGLE_PRECISION_COMPLEX
633 bind(C, name="elpa_generalized_eigenvalues_a_h_a_fc")
634#endif
635#endif
636 type(c_ptr), intent(in), value :: handle, a_p, b_p, ev_p
637 integer(kind=c_int), intent(in), value :: is_already_decomposed
638#ifdef USE_FORTRAN2008
639 integer(kind=c_int), optional, intent(in) :: error
640#else
641 integer(kind=c_int), intent(in) :: error
642#endif
643
644 math_datatype(kind=c_datatype_kind), pointer :: a(:, :), b(:, :)
645 real(kind=c_real_datatype), pointer :: ev(:)
646 logical :: is_already_decomposed_fortran
647 type(elpa_impl_t), pointer :: self
648
649 call c_f_pointer(handle, self)
650 call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
651 call c_f_pointer(b_p, b, [self%local_nrows, self%local_ncols])
652 call c_f_pointer(ev_p, ev, [self%na])
653 if(is_already_decomposed .eq. 0) then
654 is_already_decomposed_fortran = .false.
655 else
656 is_already_decomposed_fortran = .true.
657 end if
658
659 call elpa_generalized_eigenvalues_a_h_a_&
660 &elpa_impl_suffix&
661 & (self, a, b, ev, is_already_decomposed_fortran, error)
662 end subroutine
663
664
665 !> \brief elpa_generalized_eigenvalues_d_ptr: class method to solve the eigenvalue problem, using device pointers
666 !>
667 !> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
668 !> blocksize, the number of eigenvectors
669 !> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
670 !> with the class method "setup"
671 !>
672 !> It is possible to change the behaviour of the method by setting tunable parameters with the
673 !> class method "set"
674 !>
675 !> Parameters
676 !>
677 !> \param a Distributed matrix for which eigenvalues are to be computed.
678 !> Distribution is like in Scalapack.
679 !> The full matrix must be set (not only one half like in scalapack).
680 !> Destroyed on exit (upper and lower half).
681 !>
682 !> \param b Distributed matrix, part of the generalized eigenvector problem, or the
683 !> product of a previous call to this function (see is_already_decomposed).
684 !> Distribution is like in Scalapack.
685 !> If is_already_decomposed is false, on exit replaced by the decomposition
686 !>
687 !> \param ev On output: eigenvalues of a, every processor gets the complete set
688 !>
689 !> \param is_already_decomposed has to be set to .false. for the first call with a given b and .true. for
690 !> each subsequent call with the same b, since b then already contains
691 !> decomposition and thus the decomposing step is skipped
692 !>
693 !> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
694subroutine elpa_generalized_eigenvalues_d_ptr_&
695 &elpa_impl_suffix&
696 & (self, adev, bdev, evdev, is_already_decomposed, error)
697 use elpa1_impl
698 use elpa2_impl
699 use elpa_utilities, only : error_unit
700 use elpa_gpu
701 use mod_query_gpu_usage
702 use mod_check_for_gpu
703
704 use, intrinsic :: iso_c_binding
705 class(elpa_impl_t) :: self
706
707 type(c_ptr) :: aDev, bDev, evDev
708 type(c_ptr) :: tmpDev
709
710 logical :: is_already_decomposed
711 integer, optional :: error
712 integer :: error_l
713
714 logical :: success_l, wantDebug
715 integer(kind=c_int) :: solver, debug
716
717 logical :: useGPU, successGPU
718 integer(kind=c_int) :: myid, numberOfGPUDevices
719 integer(kind=c_intptr_t), parameter :: size_of_datatype = size_of_&
720 &precision&
721 &_&
722 &math_datatype
723
724 error_l = -10
725 success_l = .false.
726 if (present(error)) then
727 error = error_l
728 endif
729
730 call self%get("debug", debug, error_l)
731 if (error_l .ne. elpa_ok) then
732 write(error_unit,*) "elpa_generalized_eigenvalues_d_ptr: Problem getting option for debug settings. Aborting..."
733 endif
734 wantdebug = (debug == 1)
735
736! PETERDEBUG: new: check whether gpu keywords are set and check number of available GPUs
737 usegpu = .false.
738#if defined(WITH_NVIDIA_GPU_VERSION) || defined(WITH_AMD_GPU_VERSION) || defined(WITH_OPENMP_OFFLOAD_GPU_VERSION) || defined(WITH_SYCL_GPU_VERSION)
739 if (.not.(query_gpu_usage(self, "elpa_generalized_eigenvalues_d_ptr", usegpu))) then
740 write(error_unit,*) "elpa_generalized_eigenvalues_d_ptr: Problem getting options for GPU. Aborting..."
741 error_l = elpa_error
742 return
743 endif
744
745 if (usegpu) then
746 myid = self%mpi_setup%myRank_comm_parent
747 call self%timer%start("check_for_gpu")
748
749 if (check_for_gpu(self, myid, numberofgpudevices, wantdebug=wantdebug)) then
750 call set_gpu_parameters()
751 else
752 write(error_unit, *) "GPUs are requested but not detected! Aborting..."
753 call self%timer%stop("check_for_gpu")
754 error_l = elpa_error
755 return
756 endif
757 call self%timer%stop("check_for_gpu")
758 endif ! useGPU
759#endif
760
761 successgpu = gpu_malloc(tmpdev, self%local_ncols*self%local_nrows * size_of_datatype)
762 check_alloc_gpu("elpa_generalized_eigenvalues_d_ptr tmpDev", successgpu)
763
764#if defined(INCLUDE_ROUTINES)
765 call self%elpa_transform_generalized_d_ptr_&
766 &elpa_impl_suffix&
767 & (adev, bdev, tmpdev, is_already_decomposed, error_l)
768#endif
769
770 if (present(error)) then
771 error = error_l
772 else if (error_l .ne. elpa_ok) then
773 write(error_unit,'(a)') "ELPA: Error in elpa_generalized_eigenvalues_d_ptr() and you did not check for errors!"
774 endif
775
776 successgpu = gpu_free(tmpdev)
777 check_dealloc_gpu("elpa_generalized_eigenvalues_d_ptr tmpDev", successgpu)
778
779 call self%get("solver", solver,error_l)
780 if (solver .eq. elpa_solver_1stage) then
781#if defined(INCLUDE_ROUTINES)
782 success_l = elpa_solve_evp_&
783 &math_datatype&
784 &_1stage_d_ptr_&
785 &precision&
786 &_impl(self, adev, evdev)
787#endif
788 else if (solver .eq. elpa_solver_2stage) then
789#if defined(INCLUDE_ROUTINES)
790 success_l = elpa_solve_evp_&
791 &math_datatype&
792 &_2stage_d_ptr_&
793 &precision&
794 &_impl(self, adev, evdev)
795#endif
796 else
797 write(error_unit,'(a)') "Unknown solver: Aborting!"
798#ifdef USE_FORTRAN2008
799 if (present(error)) then
800 error = elpa_error
801 return
802 else
803 return
804 endif
805#else
806 error = elpa_error
807 return
808#endif
809 endif
810
811 if (present(error)) then
812 if (success_l) then
813 error = elpa_ok
814 else
815 error = elpa_error
816 endif
817 else if (.not. success_l) then
818 write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
819 endif
820
821end subroutine
822
823#ifdef REALCASE
824#ifdef DOUBLE_PRECISION_REAL
825 !c> void elpa_generalized_eigenvalues_d_ptr_d(elpa_t handle, double *a, double *b, double *ev,
826 !c> int is_already_decomposed, int *error);
827#endif
828#ifdef SINGLE_PRECISION_REAL
829 !c> void elpa_generalized_eigenvalues_d_ptr_f(elpa_t handle, float *a, float *b, float *ev,
830 !c> int is_already_decomposed, int *error);
831#endif
832#endif
833#ifdef COMPLEXCASE
834#ifdef DOUBLE_PRECISION_COMPLEX
835 !c> void elpa_generalized_eigenvalues_d_ptr_dc(elpa_t handle, double_complex *a, double_complex *b, double *ev,
836 !c> int is_already_decomposed, int *error);
837#endif
838#ifdef SINGLE_PRECISION_COMPLEX
839 !c> void elpa_generalized_eigenvalues_d_ptr_fc(elpa_t handle, float_complex *a, float_complex *b, float *ev,
840 !c> int is_already_decomposed, int *error);
841#endif
842#endif
843 subroutine elpa_generalized_eigenvalues_d_ptr_&
844 &elpa_impl_suffix&
845 &_c(handle, a_p, b_p, ev_p, is_already_decomposed, error) &
846#ifdef REALCASE
847#ifdef DOUBLE_PRECISION_REAL
848 bind(C, name="elpa_generalized_eigenvalues_d_ptr_d")
849#endif
850#ifdef SINGLE_PRECISION_REAL
851 bind(C, name="elpa_generalized_eigenvalues_d_ptr_f")
852#endif
853#endif
854#ifdef COMPLEXCASE
855#ifdef DOUBLE_PRECISION_COMPLEX
856 bind(C, name="elpa_generalized_eigenvalues_d_ptr_dc")
857#endif
858#ifdef SINGLE_PRECISION_COMPLEX
859 bind(C, name="elpa_generalized_eigenvalues_d_ptr_fc")
860#endif
861#endif
862 type(c_ptr), intent(in), value :: handle, a_p, b_p, ev_p
863 integer(kind=c_int), intent(in), value :: is_already_decomposed
864#ifdef USE_FORTRAN2008
865 integer(kind=c_int), optional, intent(in) :: error
866#else
867 integer(kind=c_int), intent(in) :: error
868#endif
869
870 ! MATH_DATATYPE(kind=C_DATATYPE_KIND), pointer :: a(:, :), b(:, :)
871 ! real(kind=C_REAL_DATATYPE), pointer :: ev(:)
872 logical :: is_already_decomposed_fortran
873 type(elpa_impl_t), pointer :: self
874
875 call c_f_pointer(handle, self)
876 ! call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
877 ! call c_f_pointer(b_p, b, [self%local_nrows, self%local_ncols])
878 ! call c_f_pointer(ev_p, ev, [self%na])
879 if(is_already_decomposed .eq. 0) then
880 is_already_decomposed_fortran = .false.
881 else
882 is_already_decomposed_fortran = .true.
883 end if
884
885 call elpa_generalized_eigenvalues_d_ptr_&
886 &elpa_impl_suffix&
887 & (self, a_p, b_p, ev_p, is_already_decomposed_fortran, error)
888 end subroutine
void set_gpu_parameters(int *gpuMemcpyHostToDevice, int *gpuMemcpyDeviceToHost)
Definition gpu_vendor_agnostic_layer.c:62