Commit ed963673 authored by Andreas Marek's avatar Andreas Marek
Browse files

Template for elpa_impl

parent a87aa965
......@@ -85,7 +85,8 @@ EXTRA_libelpa@SUFFIX@_private_la_DEPENDENCIES = \
src/elpa1/elpa_reduce_add_vectors.F90 \
src/elpa1/elpa_transpose_vectors.F90 \
src/elpa_api_math_template.F90 \
src/elpa_impl_template.F90 \
src/elpa_impl_math_template.F90 \
src/elpa_impl_generalized_transform_template.F90 \
src/elpa1/elpa1_compute_template.F90 \
src/elpa2/elpa2_compute_real_template.F90 \
src/elpa2/elpa2_compute_complex_template.F90 \
......@@ -659,7 +660,8 @@ EXTRA_DIST = \
nvcc_wrap \
src/GPU/cuUtils_template.cu \
src/elpa_api_math_template.F90 \
src/elpa_impl_template.F90 \
src/elpa_impl_math_template.F90 \
src/elpa_impl_generalized_transform.F90 \
src/elpa1/elpa1_compute_template.F90 \
src/elpa1/elpa1_merge_systems_real_template.F90 \
src/elpa1/elpa1_solve_tridi_real_template.F90 \
......
......@@ -31,7 +31,7 @@ AC_SUBST([ELPA_SO_VERSION], [11:0:0])
# API Version
AC_DEFINE([EARLIEST_API_VERSION], [20170403], [Earliest supported ELPA API version])
AC_DEFINE([CURRENT_API_VERSION], [20171201], [Current ELPA API version])
AC_DEFINE([CURRENT_API_VERSION], [20180301], [Current ELPA API version])
# Autotune Version
AC_DEFINE([EARLIEST_AUTOTUNE_VERSION], [20171201], [Earliest ELPA API version, which supports autotuning])
......
......@@ -18,6 +18,7 @@ config-f90.h: config.h
generated_headers += elpa/elpa_generated.h
elpa/elpa_generated.h: $(top_srcdir)/src/elpa_impl.F90 \
$(top_srcdir)/src/elpa_impl_math_template.F90 \
$(top_srcdir)/src/elpa_api.F90 | elpa
@rm -f $@
$(call extract_interface,!c>)
......
......@@ -513,14 +513,12 @@ module elpa_api
#undef REALCASE
#undef DOUBLE_PRECISION
#ifdef WANT_SINGLE_PRECISION_REAL
#define REALCASE 1
#define SINGLE_PRECISION 1
#include "general/precision_macros.h"
#include "elpa_api_math_template.F90"
#undef REALCASE
#undef SINGLE_PRECISION
#endif /* WANT_SINGLE_PRECISION_REAL */
#define COMPLEXCASE 1
#define DOUBLE_PRECISION 1
......@@ -529,14 +527,12 @@ module elpa_api
#undef DOUBLE_PRECISION
#undef COMPLEXCASE
#ifdef WANT_SINGLE_PRECISION_COMPLEX
#define COMPLEXCASE 1
#define SINGLE_PRECISION
#include "general/precision_macros.h"
#include "elpa_api_math_template.F90"
#undef COMPLEXCASE
#undef SINGLE_PRECISION
#endif /* WANT_SINGLE_PRECISION_COMPLEX */
! end of math routines
......
......@@ -622,2491 +622,6 @@ module elpa_impl
end subroutine
!> \brief elpa_eigenvectors_d: class method to solve the eigenvalue problem for double real matrices
!>
!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
!> blocksize, the number of eigenvectors
!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
!> with the class method "setup"
!>
!> It is possible to change the behaviour of the method by setting tunable parameters with the
!> class method "set"
!>
!> Parameters
!>
!> \param a Distributed matrix for which eigenvalues are to be computed.
!> Distribution is like in Scalapack.
!> The full matrix must be set (not only one half like in scalapack).
!> Destroyed on exit (upper and lower half).
!>
!> \param ev On output: eigenvalues of a, every processor gets the complete set
!>
!> \param q On output: Eigenvectors of a
!> Distribution is like in Scalapack.
!> Must be always dimensioned to the full size (corresponding to (na,na))
!> even if only a part of the eigenvalues is needed.
!>
!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
subroutine elpa_eigenvectors_d(self, a, ev, q, error)
class(elpa_impl_t) :: self
#ifdef USE_ASSUMED_SIZE
real(kind=c_double) :: a(self%local_nrows, *), q(self%local_nrows, *)
#else
real(kind=c_double) :: a(self%local_nrows, self%local_ncols), q(self%local_nrows, self%local_ncols)
#endif
real(kind=c_double) :: ev(self%na)
#ifdef USE_FORTRAN2008
integer, optional :: error
#else
integer :: error
#endif
integer :: error2
integer(kind=c_int) :: solver
logical :: success_l
call self%get("solver", solver,error2)
if (error2 .ne. ELPA_OK) then
print *,"Problem setting option. Aborting..."
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
error = error2
endif
#else
error = error2
#endif
if (solver .eq. ELPA_SOLVER_1STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_real_1stage_double_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else if (solver .eq. ELPA_SOLVER_2STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_real_2stage_double_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else
print *,"unknown solver"
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
else if (.not. success_l) then
write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
endif
#else
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
#endif
end subroutine
!c> void elpa_eigenvectors_d(elpa_t handle, double *a, double *ev, double *q, int *error);
subroutine elpa_eigenvectors_d_c(handle, a_p, ev_p, q_p, error) bind(C, name="elpa_eigenvectors_d")
type(c_ptr), intent(in), value :: handle, a_p, ev_p, q_p
#ifdef USE_FORTRAN2008
integer(kind=c_int), optional, intent(in) :: error
#else
integer(kind=c_int), intent(in) :: error
#endif
real(kind=c_double), pointer :: a(:, :), q(:, :), ev(:)
type(elpa_impl_t), pointer :: self
call c_f_pointer(handle, self)
call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
call c_f_pointer(ev_p, ev, [self%na])
call c_f_pointer(q_p, q, [self%local_nrows, self%local_ncols])
call elpa_eigenvectors_d(self, a, ev, q, error)
end subroutine
!> \brief elpa_eigenvectors_f: class method to solve the eigenvalue problem for float real matrices
!>
!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
!> blocksize, the number of eigenvectors
!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
!> with the class method "setup"
!>
!> It is possible to change the behaviour of the method by setting tunable parameters with the
!> class method "set"
!>
!> Parameters
!>
!> \param a Distributed matrix for which eigenvalues are to be computed.
!> Distribution is like in Scalapack.
!> The full matrix must be set (not only one half like in scalapack).
!> Destroyed on exit (upper and lower half).
!>
!> \param ev On output: eigenvalues of a, every processor gets the complete set
!>
!> \param q On output: Eigenvectors of a
!> Distribution is like in Scalapack.
!> Must be always dimensioned to the full size (corresponding to (na,na))
!> even if only a part of the eigenvalues is needed.
!>
!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
subroutine elpa_eigenvectors_f(self, a, ev, q, error)
class(elpa_impl_t) :: self
#ifdef USE_ASSUMED_SIZE
real(kind=c_float) :: a(self%local_nrows, *), q(self%local_nrows, *)
#else
real(kind=c_float) :: a(self%local_nrows, self%local_ncols), q(self%local_nrows, self%local_ncols)
#endif
real(kind=c_float) :: ev(self%na)
#ifdef USE_FORTRAN2008
integer, optional :: error
#else
integer :: error
#endif
integer :: error2
integer(kind=c_int) :: solver
#ifdef WANT_SINGLE_PRECISION_REAL
logical :: success_l
call self%get("solver",solver, error2)
if (error2 .ne. ELPA_OK) then
print *,"Problem getting option. Aborting..."
stop
endif
#if USE_FORTRAN2008
if (present(error)) then
error = error2
endif
#else
error = error2
#endif
if (solver .eq. ELPA_SOLVER_1STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_real_1stage_single_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else if (solver .eq. ELPA_SOLVER_2STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_real_2stage_single_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else
print *,"unknown solver"
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
else if (.not. success_l) then
write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
endif
#else
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
#endif
#else
print *,"This installation of the ELPA library has not been build with single-precision support"
error = ELPA_ERROR
#endif
end subroutine
!c> void elpa_eigenvectors_f(elpa_t handle, float *a, float *ev, float *q, int *error);
subroutine elpa_eigenvectors_f_c(handle, a_p, ev_p, q_p, error) bind(C, name="elpa_eigenvectors_f")
type(c_ptr), intent(in), value :: handle, a_p, ev_p, q_p
#ifdef USE_FORTRAN2008
integer(kind=c_int), optional, intent(in) :: error
#else
integer(kind=c_int), intent(in) :: error
#endif
real(kind=c_float), pointer :: a(:, :), q(:, :), ev(:)
type(elpa_impl_t), pointer :: self
call c_f_pointer(handle, self)
call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
call c_f_pointer(ev_p, ev, [self%na])
call c_f_pointer(q_p, q, [self%local_nrows, self%local_ncols])
call elpa_eigenvectors_f(self, a, ev, q, error)
end subroutine
!> \brief elpa_eigenvectors_dc: class method to solve the eigenvalue problem for double complex matrices
!>
!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
!> blocksize, the number of eigenvectors
!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
!> with the class method "setup"
!>
!> It is possible to change the behaviour of the method by setting tunable parameters with the
!> class method "set"
!>
!> Parameters
!>
!> \param a Distributed matrix for which eigenvalues are to be computed.
!> Distribution is like in Scalapack.
!> The full matrix must be set (not only one half like in scalapack).
!> Destroyed on exit (upper and lower half).
!>
!> \param ev On output: eigenvalues of a, every processor gets the complete set
!>
!> \param q On output: Eigenvectors of a
!> Distribution is like in Scalapack.
!> Must be always dimensioned to the full size (corresponding to (na,na))
!> even if only a part of the eigenvalues is needed.
!>
!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
subroutine elpa_eigenvectors_dc(self, a, ev, q, error)
class(elpa_impl_t) :: self
#ifdef USE_ASSUMED_SIZE
complex(kind=c_double_complex) :: a(self%local_nrows, *), q(self%local_nrows, *)
#else
complex(kind=c_double_complex) :: a(self%local_nrows, self%local_ncols), q(self%local_nrows, self%local_ncols)
#endif
real(kind=c_double) :: ev(self%na)
#ifdef USE_FORTRAN2008
integer, optional :: error
#else
integer :: error
#endif
integer :: error2
integer(kind=c_int) :: solver
logical :: success_l
call self%get("solver", solver,error2)
if (error2 .ne. ELPA_OK) then
print *,"Problem getting option. Aborting..."
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
error = error2
endif
#else
error = error2
#endif
if (solver .eq. ELPA_SOLVER_1STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_complex_1stage_double_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else if (solver .eq. ELPA_SOLVER_2STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_complex_2stage_double_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else
print *,"unknown solver"
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
else if (.not. success_l) then
write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
endif
#else
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
#endif
end subroutine
!c> void elpa_eigenvectors_dc(elpa_t handle, double complex *a, double *ev, double complex *q, int *error);
subroutine elpa_eigenvectors_dc_c(handle, a_p, ev_p, q_p, error) bind(C, name="elpa_eigenvectors_dc")
type(c_ptr), intent(in), value :: handle, a_p, ev_p, q_p
#ifdef USE_FORTRAN2008
integer(kind=c_int), optional, intent(in) :: error
#else
integer(kind=c_int), intent(in) :: error
#endif
complex(kind=c_double_complex), pointer :: a(:, :), q(:, :)
real(kind=c_double), pointer :: ev(:)
type(elpa_impl_t), pointer :: self
call c_f_pointer(handle, self)
call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
call c_f_pointer(ev_p, ev, [self%na])
call c_f_pointer(q_p, q, [self%local_nrows, self%local_ncols])
call elpa_eigenvectors_dc(self, a, ev, q, error)
end subroutine
!> \brief elpa_eigenvectors_fc: class method to solve the eigenvalue problem for float complex matrices
!>
!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
!> blocksize, the number of eigenvectors
!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
!> with the class method "setup"
!>
!> It is possible to change the behaviour of the method by setting tunable parameters with the
!> class method "set"
!>
!> Parameters
!>
!> \param a Distributed matrix for which eigenvalues are to be computed.
!> Distribution is like in Scalapack.
!> The full matrix must be set (not only one half like in scalapack).
!> Destroyed on exit (upper and lower half).
!>
!> \param ev On output: eigenvalues of a, every processor gets the complete set
!>
!> \param q On output: Eigenvectors of a
!> Distribution is like in Scalapack.
!> Must be always dimensioned to the full size (corresponding to (na,na))
!> even if only a part of the eigenvalues is needed.
!>
!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
subroutine elpa_eigenvectors_fc(self, a, ev, q, error)
class(elpa_impl_t) :: self
#ifdef USE_ASSUMED_SIZE
complex(kind=c_float_complex) :: a(self%local_nrows, *), q(self%local_nrows, *)
#else
complex(kind=c_float_complex) :: a(self%local_nrows, self%local_ncols), q(self%local_nrows, self%local_ncols)
#endif
real(kind=c_float) :: ev(self%na)
#ifdef USE_FORTRAN2008
integer, optional :: error
#else
integer :: error
#endif
integer :: error2
integer(kind=c_int) :: solver
#ifdef WANT_SINGLE_PRECISION_COMPLEX
logical :: success_l
call self%get("solver", solver,error2)
if (error2 .ne. ELPA_OK) then
print *,"Problem getting option. Aborting..."
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
error = error2
endif
#else
error = error2
#endif
if (solver .eq. ELPA_SOLVER_1STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_complex_1stage_single_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else if (solver .eq. ELPA_SOLVER_2STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_complex_2stage_single_impl(self, a, ev, q)
call self%autotune_timer%stop("accumulator")
else
print *,"unknown solver"
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
else if (.not. success_l) then
write(error_unit,'(a)') "ELPA: Error in solve() and you did not check for errors!"
endif
#else
if (success_l) then
error = ELPA_OK
else
error = ELPA_ERROR
endif
#endif
#else
print *,"This installation of the ELPA library has not been build with single-precision support"
error = ELPA_ERROR
#endif
end subroutine
!c> void elpa_eigenvectors_fc(elpa_t handle, float complex *a, float *ev, float complex *q, int *error);
subroutine elpa_eigenvectors_fc_c(handle, a_p, ev_p, q_p, error) bind(C, name="elpa_eigenvectors_fc")
type(c_ptr), intent(in), value :: handle, a_p, ev_p, q_p
#ifdef USE_FORTRAN2008
integer(kind=c_int), optional, intent(in) :: error
#else
integer(kind=c_int), intent(in) :: error
#endif
complex(kind=c_float_complex), pointer :: a(:, :), q(:, :)
real(kind=c_float), pointer :: ev(:)
type(elpa_impl_t), pointer :: self
call c_f_pointer(handle, self)
call c_f_pointer(a_p, a, [self%local_nrows, self%local_ncols])
call c_f_pointer(ev_p, ev, [self%na])
call c_f_pointer(q_p, q, [self%local_nrows, self%local_ncols])
call elpa_eigenvectors_fc(self, a, ev, q, error)
end subroutine
!> \brief elpa_eigenvalues_d: class method to solve the eigenvalue problem for double real matrices
!>
!> The dimensions of the matrix a (locally ditributed and global), the block-cyclic distribution
!> blocksize, the number of eigenvectors
!> to be computed and the MPI communicators are already known to the object and MUST be set BEFORE
!> with the class method "setup"
!>
!> It is possible to change the behaviour of the method by setting tunable parameters with the
!> class method "set"
!>
!> Parameters
!>
!> \param a Distributed matrix for which eigenvalues are to be computed.
!> Distribution is like in Scalapack.
!> The full matrix must be set (not only one half like in scalapack).
!> Destroyed on exit (upper and lower half).
!>
!> \param ev On output: eigenvalues of a, every processor gets the complete set
!>
!> \param error integer, optional: returns an error code, which can be queried with elpa_strerr
subroutine elpa_eigenvalues_d(self, a, ev, error)
class(elpa_impl_t) :: self
#ifdef USE_ASSUMED_SIZE
real(kind=c_double) :: a(self%local_nrows, *)
#else
real(kind=c_double) :: a(self%local_nrows, self%local_ncols)
#endif
real(kind=c_double) :: ev(self%na)
#ifdef USE_FORTRAN2008
integer, optional :: error
#else
integer :: error
#endif
integer :: error2
integer(kind=c_int) :: solver
logical :: success_l
call self%get("solver", solver,error2)
if (error2 .ne. ELPA_OK) then
print *,"Problem getting option. Aborting..."
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
error = error2
endif
#else
error = error2
#endif
if (solver .eq. ELPA_SOLVER_1STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_real_1stage_double_impl(self, a, ev)
call self%autotune_timer%stop("accumulator")
else if (solver .eq. ELPA_SOLVER_2STAGE) then
call self%autotune_timer%start("accumulator")
success_l = elpa_solve_evp_real_2stage_double_impl(self, a, ev)
call self%autotune_timer%stop("accumulator")
else
print *,"unknown solver"
stop
endif
#ifdef USE_FORTRAN2008
if (present(error)) then
if (success_l