LCOV - code coverage report
Current view: top level - test/shared - test_check_correctness_template.F90 (source / functions) Hit Total Coverage
Test: coverage_50ab7a7628bba174fc62cee3ab72b26e81f87fe5.info Lines: 154 184 83.7 %
Date: 2018-01-10 09:29:53 Functions: 21 24 87.5 %

          Line data    Source code
       1             : !    This file is part of ELPA.
       2             : !
       3             : !    The ELPA library was originally created by the ELPA consortium,
       4             : !    consisting of the following organizations:
       5             : !
       6             : !    - Max Planck Computing and Data Facility (MPCDF), formerly known as
       7             : !      Rechenzentrum Garching der Max-Planck-Gesellschaft (RZG),
       8             : !    - Bergische Universität Wuppertal, Lehrstuhl für angewandte
       9             : !      Informatik,
      10             : !    - Technische Universität München, Lehrstuhl für Informatik mit
      11             : !      Schwerpunkt Wissenschaftliches Rechnen ,
      12             : !    - Fritz-Haber-Institut, Berlin, Abt. Theorie,
      13             : !    - Max-Plack-Institut für Mathematik in den Naturwissenschaften,
      14             : !      Leipzig, Abt. Komplexe Strukutren in Biologie und Kognition,
      15             : !      and
      16             : !    - IBM Deutschland GmbH
      17             : !
      18             : !
      19             : !    More information can be found here:
      20             : !    http://elpa.mpcdf.mpg.de/
      21             : !
      22             : !    ELPA is free software: you can redistribute it and/or modify
      23             : !    it under the terms of the version 3 of the license of the
      24             : !    GNU Lesser General Public License as published by the Free
      25             : !    Software Foundation.
      26             : !
      27             : !    ELPA is distributed in the hope that it will be useful,
      28             : !    but WITHOUT ANY WARRANTY; without even the implied warranty of
      29             : !    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      30             : !    GNU Lesser General Public License for more details.
      31             : !
      32             : !    You should have received a copy of the GNU Lesser General Public License
      33             : !    along with ELPA.  If not, see <http://www.gnu.org/licenses/>
      34             : !
      35             : !    ELPA reflects a substantial effort on the part of the original
      36             : !    ELPA consortium, and we ask you to respect the spirit of the
      37             : !    license that we chose: i.e., please contribute any changes you
      38             : !    may have back to the original ELPA library distribution, and keep
      39             : !    any derivatives of ELPA under the same license that we chose for
      40             : !    the original distribution, the GNU Lesser General Public License.
      41             : !
      42             : ! Author: A. Marek, MPCDF
      43             : 
      44       31536 :     function check_correctness_evp_numeric_residuals_&
      45             :     &MATH_DATATYPE&
      46             :     &_&
      47             :     &PRECISION&
      48       31536 :     & (na, nev, as, z, ev, sc_desc, nblk, myid, np_rows, np_cols, my_prow, my_pcol, bs) result(status)
      49             :       implicit none
      50             : #include "../../src/general/precision_kinds.F90"
      51             :       integer(kind=ik)                 :: status
      52             :       integer(kind=ik), intent(in)     :: na, nev, nblk, myid, np_rows, np_cols, my_prow, my_pcol
      53             :       MATH_DATATYPE(kind=rck), intent(in)           :: as(:,:), z(:,:)
      54             :       MATH_DATATYPE(kind=rck), intent(in), optional :: bs(:,:)
      55             :       real(kind=rk)                 :: ev(:)
      56       63072 :       MATH_DATATYPE(kind=rck), dimension(size(as,dim=1),size(as,dim=2)) :: tmp1, tmp2
      57             :       MATH_DATATYPE(kind=rck)                :: xc
      58             : 
      59             : #ifndef WITH_MPI
      60             : #if REALCASE == 1
      61             :       real(kind=rck)                   :: dnrm2, snrm2
      62             : #endif
      63             : #if COMPLEXCASE == 1
      64             :       complex(kind=rck)                :: zdotc, cdotc
      65             : #endif /* COMPLEXCASE */
      66             : #endif
      67             : 
      68             :       integer(kind=ik)                 :: sc_desc(:)
      69             : 
      70             :       integer(kind=ik)                 :: i, rowLocal, colLocal
      71             :       real(kind=rck)                   :: err, errmax
      72             : 
      73             :       integer :: mpierr
      74             : 
      75             :       ! tolerance for the residual test for different math type/precision setups
      76             :       real(kind=rk), parameter       :: tol_res_real_double      = 5e-12_rk
      77             :       real(kind=rk), parameter       :: tol_res_real_single      = 3e-2_rk
      78             :       real(kind=rk), parameter       :: tol_res_complex_double   = 5e-12_rk
      79             :       real(kind=rk), parameter       :: tol_res_complex_single   = 3e-2_rk
      80             :       real(kind=rk)                  :: tol_res                  = tol_res_&
      81             :                                                                           &MATH_DATATYPE&
      82             :                                                                           &_&
      83             :                                                                           &PRECISION
      84             :       ! precision of generalized problem is lower
      85             :       real(kind=rk), parameter       :: generalized_penalty = 10.0_rk
      86             : 
      87             :       ! tolerance for the orthogonality test for different math type/precision setups
      88             :       real(kind=rk), parameter       :: tol_orth_real_double     = 5e-11_rk
      89             :       real(kind=rk), parameter       :: tol_orth_real_single     = 9e-2_rk
      90             :       real(kind=rk), parameter       :: tol_orth_complex_double  = 5e-11_rk
      91             :       real(kind=rk), parameter       :: tol_orth_complex_single  = 9e-3_rk
      92             :       real(kind=rk), parameter       :: tol_orth                 = tol_orth_&
      93             :                                                                           &MATH_DATATYPE&
      94             :                                                                           &_&
      95             :                                                                           &PRECISION
      96             : 
      97       31536 :       if(present(bs)) then
      98           0 :           tol_res = generalized_penalty * tol_res
      99             :       endif
     100       31536 :       status = 0
     101             : 
     102             :       ! 1. Residual (maximum of || A*Zi - Zi*EVi ||)
     103             : 
     104             :       ! tmp1 = Zi*EVi
     105       31536 :       tmp1(:,:) = z(:,:)
     106     5232336 :       do i=1,nev
     107     5200800 :         xc = ev(i)
     108             : #ifdef WITH_MPI
     109             :         call p&
     110             :             &BLAS_CHAR&
     111     3486400 :             &scal(na, xc, tmp1, 1, i, sc_desc, 1)
     112             : #else /* WITH_MPI */
     113             :         call BLAS_CHAR&
     114     1714400 :             &scal(na,xc,tmp1(:,i),1)
     115             : #endif /* WITH_MPI */
     116             :       enddo
     117             : 
     118             :       ! for generalized EV problem, multiply by bs as well
     119             :       ! tmp2 = B * tmp1
     120       31536 :       if(present(bs)) then
     121             : #ifdef WITH_MPI
     122             :       call scal_PRECISION_GEMM('N', 'N', na, nev, na, ONE, bs, 1, 1, sc_desc, &
     123           0 :                   tmp1, 1, 1, sc_desc, ZERO, tmp2, 1, 1, sc_desc)
     124             : #else /* WITH_MPI */
     125           0 :       call PRECISION_GEMM('N','N',na,nev,na,ONE,bs,na,tmp1,na,ZERO,tmp2,na)
     126             : #endif /* WITH_MPI */
     127             :       else
     128             :         ! normal eigenvalue problem .. no need to multiply
     129       31536 :         tmp2(:,:) = tmp1(:,:)
     130             :       end if
     131             : 
     132             :       ! tmp1 =  A * Z
     133             :       ! as is original stored matrix, Z are the EVs
     134             : #ifdef WITH_MPI
     135             :       call scal_PRECISION_GEMM('N', 'N', na, nev, na, ONE, as, 1, 1, sc_desc, &
     136       21152 :                   z, 1, 1, sc_desc, ZERO, tmp1, 1, 1, sc_desc)
     137             : #else /* WITH_MPI */
     138       10384 :       call PRECISION_GEMM('N','N',na,nev,na,ONE,as,na,z,na,ZERO,tmp1,na)
     139             : #endif /* WITH_MPI */
     140             : 
     141             :       !  tmp1 = A*Zi - Zi*EVi
     142       31536 :       tmp1(:,:) =  tmp1(:,:) - tmp2(:,:)
     143             : 
     144             :       ! Get maximum norm of columns of tmp1
     145       31536 :       errmax = 0.0_rk
     146             : 
     147     5232336 :       do i=1,nev
     148             : #if REALCASE == 1
     149     2863200 :         err = 0.0_rk
     150             : #ifdef WITH_MPI
     151     1918400 :         call scal_PRECISION_NRM2(na, err, tmp1, 1, i, sc_desc, 1)
     152             : #else /* WITH_MPI */
     153      944800 :         err = PRECISION_NRM2(na,tmp1(1,i),1)
     154             : #endif /* WITH_MPI */
     155     2863200 :         errmax = max(errmax, err)
     156             : #endif /* REALCASE */
     157             : 
     158             : #if COMPLEXCASE == 1
     159     2337600 :         xc = 0
     160             : #ifdef WITH_MPI
     161     1568000 :         call scal_PRECISION_DOTC(na, xc, tmp1, 1, i, sc_desc, 1, tmp1, 1, i, sc_desc, 1)
     162             : #else /* WITH_MPI */
     163      769600 :         xc = PRECISION_DOTC(na,tmp1,1,tmp1,1)
     164             : #endif /* WITH_MPI */
     165     2337600 :         errmax = max(errmax, sqrt(real(xc,kind=REAL_DATATYPE)))
     166             : #endif /* COMPLEXCASE */
     167             :       enddo
     168             : 
     169             :       ! Get maximum error norm over all processors
     170       31536 :       err = errmax
     171             : #ifdef WITH_MPI
     172       21152 :       call mpi_allreduce(err, errmax, 1, MPI_REAL_PRECISION, MPI_MAX, MPI_COMM_WORLD, mpierr)
     173             : #else /* WITH_MPI */
     174       10384 :       errmax = err
     175             : #endif /* WITH_MPI */
     176       31536 :       if (myid==0) print *,'Results of numerical residual checks:'
     177       31536 :       if (myid==0) print *,'Error Residual     :',errmax
     178       31536 :       if (nev .ge. 2) then
     179       31536 :         if (errmax .gt. tol_res .or. errmax .eq. 0.0_rk) then
     180           0 :           status = 1
     181             :         endif
     182             :       else
     183           0 :         if (errmax .gt. tol_res) then
     184           0 :           status = 1
     185             :         endif
     186             :       endif
     187             : 
     188             :       ! 2. Eigenvector orthogonality
     189             :       !TODO for the generalized eigenvector problem, the orthogonality test has to be altered
     190             :       !TODO at the moment, it is skipped
     191       31536 :       if(.not. present(bs)) then
     192             :       ! tmp1 = Z**T * Z
     193       31536 :       tmp1 = 0
     194             : #ifdef WITH_MPI
     195             :       call scal_PRECISION_GEMM(BLAS_TRANS_OR_CONJ, 'N', nev, nev, na, ONE, z, 1, 1, &
     196       21152 :                         sc_desc, z, 1, 1, sc_desc, ZERO, tmp1, 1, 1, sc_desc)
     197             : #else /* WITH_MPI */
     198       10384 :       call PRECISION_GEMM(BLAS_TRANS_OR_CONJ,'N',nev,nev,na,ONE,z,na,z,na,ZERO,tmp1,na)
     199             : #endif /* WITH_MPI */
     200             :       !TODO for the C interface, not all information is passed (zeros instead)
     201             :       !TODO than this part of the test cannot be done
     202             :       !TODO either we will not have this part of test at all, or it will be improved
     203       31536 :       if(nblk > 0) then
     204             :         ! First check, whether the elements on diagonal are 1 .. "normality" of the vectors
     205       28176 :         err = 0.0_rk
     206     4254576 :         do i=1, nev
     207     4226400 :           if (map_global_array_index_to_local_index(i, i, rowLocal, colLocal, nblk, np_rows, np_cols, my_prow, my_pcol)) then
     208     2808000 :              err = max(err, abs(tmp1(rowLocal,colLocal) - 1.0_rk))
     209             :            endif
     210             :         end do
     211             : #ifdef WITH_MPI
     212       18912 :         call mpi_allreduce(err, errmax, 1, MPI_REAL_PRECISION, MPI_MAX, MPI_COMM_WORLD, mpierr)
     213             : #else /* WITH_MPI */
     214        9264 :         errmax = err
     215             : #endif /* WITH_MPI */
     216       28176 :         if (myid==0) print *,'Maximal error in eigenvector lengths:',errmax
     217             :       end if
     218             : 
     219             :       ! Second, find the maximal error in the whole Z**T * Z matrix (its diference from identity matrix)
     220             :       ! Initialize tmp2 to unit matrix
     221       31536 :       tmp2 = 0
     222             : #ifdef WITH_MPI
     223       21152 :       call scal_PRECISION_LASET('A', nev, nev, ZERO, ONE, tmp2, 1, 1, sc_desc)
     224             : #else /* WITH_MPI */
     225       10384 :       call PRECISION_LASET('A',nev,nev,ZERO,ONE,tmp2,na)
     226             : #endif /* WITH_MPI */
     227             : 
     228             :       !      ! tmp1 = Z**T * Z - Unit Matrix
     229       31536 :       tmp1(:,:) =  tmp1(:,:) - tmp2(:,:)
     230             : 
     231             :       ! Get maximum error (max abs value in tmp1)
     232       31536 :       err = maxval(abs(tmp1))
     233             : #ifdef WITH_MPI
     234       21152 :       call mpi_allreduce(err, errmax, 1, MPI_REAL_PRECISION, MPI_MAX, MPI_COMM_WORLD, mpierr)
     235             : #else /* WITH_MPI */
     236       10384 :       errmax = err
     237             : #endif /* WITH_MPI */
     238       31536 :       if (myid==0) print *,'Error Orthogonality:',errmax
     239       31536 :         if (nev .ge. 2) then
     240       31536 :           if (errmax .gt. tol_orth .or. errmax .eq. 0.0_rk) then
     241           0 :             status = 1
     242             :           endif
     243             :         else
     244           0 :           if (errmax .gt. tol_orth) then
     245           0 :             status = 1
     246             :           endif
     247             :         endif
     248             :       endif  ! skiping test of orthogonality for generalized eigenproblem
     249       63072 :     end function
     250             : 
     251             : 
     252             : #if REALCASE == 1
     253             : 
     254             : #ifdef DOUBLE_PRECISION_REAL
     255             :     !c> int check_correctness_evp_numeric_residuals_real_double_f(int na, int nev, int na_rows, int na_cols,
     256             :     !c>                                         double *as, double *z, double *ev,
     257             :     !c>                                         int sc_desc[9], int myid);
     258             : #else
     259             :     !c> int check_correctness_evp_numeric_residuals_real_single_f(int na, int nev, int na_rows, int na_cols,
     260             :     !c>                                         float *as, float *z, float *ev,
     261             :     !c>                                         int sc_desc[9], int myid);
     262             : #endif
     263             : 
     264             : #endif /* REALCASE */
     265             : 
     266             : #if COMPLEXCASE == 1
     267             : #ifdef DOUBLE_PRECISION_COMPLEX
     268             :     !c> int check_correctness_evp_numeric_residuals_complex_double_f(int na, int nev, int na_rows, int na_cols,
     269             :     !c>                                         complex double *as, complex double *z, double *ev,
     270             :     !c>                                         int sc_desc[9], int myid);
     271             : #else
     272             :     !c> int check_correctness_evp_numeric_residuals_complex_single_f(int na, int nev, int na_rows, int na_cols,
     273             :     !c>                                         complex float *as, complex float *z, float *ev,
     274             :     !c>                                         int sc_desc[9], int myid);
     275             : #endif
     276             : #endif /* COMPLEXCASE */
     277             : 
     278        3360 : function check_correctness_evp_numeric_residuals_&
     279             : &MATH_DATATYPE&
     280             : &_&
     281             : &PRECISION&
     282        3360 : &_f (na, nev, na_rows, na_cols, as, z, ev, sc_desc, myid) result(status) &
     283             :       bind(C,name="check_correctness_evp_numeric_residuals_&
     284             :       &MATH_DATATYPE&
     285             :       &_&
     286             :       &PRECISION&
     287             :       &_f")
     288             : 
     289             :       use iso_c_binding
     290             : 
     291             :       implicit none
     292             : #include "../../src/general/precision_kinds.F90"
     293             : 
     294             :       integer(kind=c_int)            :: status
     295             :       integer(kind=c_int), value     :: na, nev, myid, na_rows, na_cols
     296             :       MATH_DATATYPE(kind=rck)     :: as(1:na_rows,1:na_cols), z(1:na_rows,1:na_cols)
     297             :       real(kind=rck)    :: ev(1:na)
     298             :       integer(kind=c_int)            :: sc_desc(1:9)
     299             : 
     300             :       ! TODO: I did not want to add all the variables to the C interface as well
     301             :       ! TODO: I think that we should find a better way to pass this information
     302             :       ! TODO: to all the functions anyway (get it from sc_desc, pass elpa_t, etc..)
     303             :       status = check_correctness_evp_numeric_residuals_&
     304             :       &MATH_DATATYPE&
     305             :       &_&
     306             :       &PRECISION&
     307        3360 :       & (na, nev, as, z, ev, sc_desc, 0, myid, 0, 0, 0, 0)
     308             : 
     309        3360 :     end function
     310             : 
     311        1440 :     function check_correctness_eigenvalues_toeplitz_&
     312             :     &MATH_DATATYPE&
     313             :     &_&
     314             :     &PRECISION&
     315        1440 :     & (na, diagonalElement, subdiagonalElement, ev, z, myid) result(status)
     316             :       use iso_c_binding
     317             :       implicit none
     318             : #include "../../src/general/precision_kinds.F90"
     319             : 
     320             :       integer               :: status, ii, j, myid
     321             :       integer, intent(in)   :: na
     322             :       real(kind=rck) :: diagonalElement, subdiagonalElement
     323        2880 :       real(kind=rck) :: ev_analytic(na), ev(na)
     324             :       MATH_DATATYPE(kind=rck) :: z(:,:)
     325             : 
     326             : #if defined(DOUBLE_PRECISION_REAL) || defined(DOUBLE_PRECISION_COMPLEX)
     327             :       real(kind=rck), parameter   :: pi = 3.141592653589793238462643383279_c_double
     328             : #else
     329             :       real(kind=rck), parameter   :: pi = 3.1415926535897932_c_float
     330             : #endif
     331             :       real(kind=rck)              :: tmp, maxerr
     332             :       integer                     :: loctmp
     333        1440 :       status = 0
     334             : 
     335             :      ! analytic solution
     336      217440 :      do ii=1, na
     337             :        ev_analytic(ii) = diagonalElement + 2.0_rk * &
     338             :                          subdiagonalElement *cos( pi*real(ii,kind=rk)/ &
     339      216000 :                          real(na+1,kind=rk) )
     340             :      enddo
     341             : 
     342             :      ! sort analytic solution:
     343             : 
     344             :      ! this hack is neither elegant, nor optimized: for huge matrixes it might be expensive
     345             :      ! a proper sorting algorithmus might be implemented here
     346             : 
     347        1440 :      tmp    = minval(ev_analytic)
     348        1440 :      loctmp = minloc(ev_analytic, 1)
     349             : 
     350        1440 :      ev_analytic(loctmp) = ev_analytic(1)
     351        1440 :      ev_analytic(1) = tmp
     352      216000 :      do ii=2, na
     353      214560 :        tmp = ev_analytic(ii)
     354    16306560 :        do j= ii, na
     355    16092000 :          if (ev_analytic(j) .lt. tmp) then
     356     7885440 :            tmp    = ev_analytic(j)
     357     7885440 :            loctmp = j
     358             :          endif
     359             :        enddo
     360      214560 :        ev_analytic(loctmp) = ev_analytic(ii)
     361      214560 :        ev_analytic(ii) = tmp
     362             :      enddo
     363             : 
     364             :      ! compute a simple error max of eigenvalues
     365        1440 :      maxerr = 0.0
     366        1440 :      maxerr = maxval( (ev(:) - ev_analytic(:))/ev_analytic(:) , 1)
     367             : 
     368             : #if defined(DOUBLE_PRECISION_REAL) || defined(DOUBLE_PRECISION_COMPLEX)
     369         960 :      if (maxerr .gt. 8.e-13_c_double .or. maxerr .eq. 0.0_c_double) then
     370             : #else
     371         480 :      if (maxerr .gt. 8.e-4_c_float .or. maxerr .eq. 0.0_c_float) then
     372             : #endif
     373           0 :        status = 1
     374           0 :        if (myid .eq. 0) then
     375           0 :          print *,"Result of Toeplitz matrix test: "
     376           0 :          print *,"Eigenvalues differ from analytic solution: maxerr = ",maxerr
     377             :        endif
     378             :      endif
     379             : 
     380        1440 :     if (status .eq. 0) then
     381        1440 :        if (myid .eq. 0) then
     382         960 :          print *,"Result of Toeplitz matrix test: test passed"
     383         960 :          print *,"Eigenvalues differ from analytic solution: maxerr = ",maxerr
     384             :        endif
     385             :     endif
     386        2880 :     end function
     387             : 
     388         576 :     function check_correctness_cholesky_&
     389             :     &MATH_DATATYPE&
     390             :     &_&
     391             :     &PRECISION&
     392         576 :     & (na, a, as, na_rows, sc_desc, myid) result(status)
     393             :       implicit none
     394             : #include "../../src/general/precision_kinds.F90"
     395             :       integer(kind=ik)                 :: status
     396             :       integer(kind=ik), intent(in)     :: na, myid, na_rows
     397             : 
     398             :       MATH_DATATYPE(kind=rck), intent(in)       :: a(:,:), as(:,:)
     399        1152 :       MATH_DATATYPE(kind=rck), dimension(size(as,dim=1),size(as,dim=2)) :: tmp1, tmp2
     400             :       real(kind=rk)                   :: norm, normmax
     401             : 
     402             : #ifdef WITH_MPI
     403             :       real(kind=rck)                   :: p&
     404             :                                            &BLAS_CHAR&
     405             :                                            &lange
     406             : #else /* WITH_MPI */
     407             :       real(kind=rck)                   :: BLAS_CHAR&
     408             :                                           &lange
     409             : #endif /* WITH_MPI */
     410             : 
     411             :       integer(kind=ik)                 :: sc_desc(:)
     412             :       real(kind=rck)                   :: err, errmax
     413             :       integer :: mpierr
     414             : 
     415         576 :       status = 0
     416         576 :       tmp1(:,:) = 0.0_rck
     417             : 
     418             : 
     419             : #if REALCASE == 1
     420             :       ! tmp1 = a**T
     421             : #ifdef WITH_MPI
     422             :       call p&
     423             :           &BLAS_CHAR&
     424         192 :           &tran(na, na, 1.0_rck, a, 1, 1, sc_desc, 0.0_rck, tmp1, 1, 1, sc_desc)
     425             : #else /* WITH_MPI */
     426          96 :       tmp1 = transpose(a)
     427             : #endif /* WITH_MPI */
     428             : #endif /* REALCASE == 1 */
     429             : 
     430             : #if COMPLEXCASE == 1
     431             :       ! tmp1 = a**H
     432             : #ifdef WITH_MPI
     433             :       call p&
     434             :             &BLAS_CHAR&
     435         192 :             &tranc(na, na, ONE, a, 1, 1, sc_desc, ZERO, tmp1, 1, 1, sc_desc)
     436             : #else /* WITH_MPI */
     437          96 :       tmp1 = transpose(conjg(a))
     438             : #endif /* WITH_MPI */
     439             : #endif /* COMPLEXCASE == 1 */
     440             : 
     441             :       ! tmp2 = a**T * a
     442             : #ifdef WITH_MPI
     443             :       call p&
     444             :             &BLAS_CHAR&
     445             :             &gemm("N","N", na, na, na, ONE, tmp1, 1, 1, sc_desc, a, 1, 1, &
     446         384 :                sc_desc, ZERO, tmp2, 1, 1, sc_desc)
     447             : #else /* WITH_MPI */
     448             :       call BLAS_CHAR&
     449         192 :                     &gemm("N","N", na, na, na, ONE, tmp1, na, a, na, ZERO, tmp2, na)
     450             : #endif /* WITH_MPI */
     451             : 
     452             :       ! compare tmp2 with original matrix
     453         576 :       tmp2(:,:) = tmp2(:,:) - as(:,:)
     454             : 
     455             : #ifdef WITH_MPI
     456             :       norm = p&
     457             :               &BLAS_CHAR&
     458         384 :               &lange("M",na, na, tmp2, 1, 1, sc_desc, tmp1)
     459             : #else /* WITH_MPI */
     460             :       norm = BLAS_CHAR&
     461         192 :              &lange("M", na, na, tmp2, na_rows, tmp1)
     462             : #endif /* WITH_MPI */
     463             : 
     464             : 
     465             : #ifdef WITH_MPI
     466         384 :       call mpi_allreduce(norm,normmax,1,MPI_REAL_PRECISION,MPI_MAX,MPI_COMM_WORLD,mpierr)
     467             : #else /* WITH_MPI */
     468         192 :       normmax = norm
     469             : #endif /* WITH_MPI */
     470             : 
     471         576 :       if (myid .eq. 0) then
     472         384 :         print *," Maximum error of result: ", normmax
     473             :       endif
     474             : 
     475             : #if REALCASE == 1
     476             : #ifdef DOUBLE_PRECISION_REAL
     477             : !      if (normmax .gt. 5e-12_rk8 .or. normmax .eq. 0.0_rk8) then
     478         192 :       if (normmax .gt. 5e-12_rk8) then
     479           0 :         status = 1
     480             :       endif
     481             : #else
     482             : !      if (normmax .gt. 5e-4_rk4 .or. normmax .eq. 0.0_rk4) then
     483          96 :       if (normmax .gt. 5e-4_rk4 ) then
     484           0 :         status = 1
     485             :       endif
     486             : #endif
     487             : #endif
     488             : 
     489             : #if COMPLEXCASE == 1
     490             : #ifdef DOUBLE_PRECISION_COMPLEX
     491             : !      if (normmax .gt. 5e-11_rk8 .or. normmax .eq. 0.0_rk8) then
     492         192 :       if (normmax .gt. 5e-11_rk8 ) then
     493           0 :         status = 1
     494             :       endif
     495             : #else
     496             : !      if (normmax .gt. 5e-3_rk4 .or. normmax .eq. 0.0_rk4) then
     497          96 :       if (normmax .gt. 5e-3_rk4) then
     498           0 :         status = 1
     499             :       endif
     500             : #endif
     501             : #endif
     502        1152 :     end function
     503             : 
     504         768 :     function check_correctness_hermitian_multiply_&
     505             :     &MATH_DATATYPE&
     506             :     &_&
     507             :     &PRECISION&
     508         768 :     & (na, a, b, c, na_rows, sc_desc, myid) result(status)
     509             :       implicit none
     510             : #include "../../src/general/precision_kinds.F90"
     511             :       integer(kind=ik)                 :: status
     512             :       integer(kind=ik), intent(in)     :: na, myid, na_rows
     513             :       MATH_DATATYPE(kind=rck), intent(in)       :: a(:,:), b(:,:), c(:,:)
     514        1536 :       MATH_DATATYPE(kind=rck), dimension(size(a,dim=1),size(a,dim=2)) :: tmp1, tmp2
     515             :       real(kind=rck)                   :: norm, normmax
     516             : 
     517             : #ifdef WITH_MPI
     518             :       real(kind=rck)                   :: p&
     519             :                                            &BLAS_CHAR&
     520             :                                            &lange
     521             : #else /* WITH_MPI */
     522             :       real(kind=rck)                   :: BLAS_CHAR&
     523             :                                           &lange
     524             : #endif /* WITH_MPI */
     525             : 
     526             :       integer(kind=ik)                 :: sc_desc(:)
     527             :       real(kind=rck)                   :: err, errmax
     528             :       integer :: mpierr
     529             : 
     530         768 :       status = 0
     531         768 :       tmp1(:,:) = ZERO
     532             : 
     533             : #if REALCASE == 1
     534             :       ! tmp1 = a**T
     535             : #ifdef WITH_MPI
     536             :       call p&
     537             :             &BLAS_CHAR&
     538         320 :             &tran(na, na, ONE, a, 1, 1, sc_desc, ZERO, tmp1, 1, 1, sc_desc)
     539             : #else /* WITH_MPI */
     540         160 :       tmp1 = transpose(a)
     541             : #endif /* WITH_MPI */
     542             : 
     543             : #endif /* REALCASE == 1 */
     544             : 
     545             : #if COMPLEXCASE == 1
     546             :       ! tmp1 = a**H
     547             : #ifdef WITH_MPI
     548             :       call p&
     549             :             &BLAS_CHAR&
     550         192 :             &tranc(na, na, ONE, a, 1, 1, sc_desc, ZERO, tmp1, 1, 1, sc_desc)
     551             : #else /* WITH_MPI */
     552          96 :       tmp1 = transpose(conjg(a))
     553             : #endif /* WITH_MPI */
     554             : #endif /* COMPLEXCASE == 1 */
     555             : 
     556             :    ! tmp2 = tmp1 * b
     557             : #ifdef WITH_MPI
     558             :    call p&
     559             :          &BLAS_CHAR&
     560             :          &gemm("N","N", na, na, na, ONE, tmp1, 1, 1, sc_desc, b, 1, 1, &
     561         512 :                sc_desc, ZERO, tmp2, 1, 1, sc_desc)
     562             : #else
     563             :    call BLAS_CHAR&
     564         256 :         &gemm("N","N", na, na, na, ONE, tmp1, na, b, na, ZERO, tmp2, na)
     565             : #endif
     566             : 
     567             :       ! compare tmp2 with c
     568         768 :       tmp2(:,:) = tmp2(:,:) - c(:,:)
     569             : 
     570             : #ifdef WITH_MPI
     571             :       norm = p&
     572             :               &BLAS_CHAR&
     573         512 :               &lange("M",na, na, tmp2, 1, 1, sc_desc, tmp1)
     574             : #else /* WITH_MPI */
     575             :       norm = BLAS_CHAR&
     576         256 :              &lange("M", na, na, tmp2, na_rows, tmp1)
     577             : #endif /* WITH_MPI */
     578             : 
     579             : #ifdef WITH_MPI
     580         512 :       call mpi_allreduce(norm,normmax,1,MPI_REAL_PRECISION,MPI_MAX,MPI_COMM_WORLD,mpierr)
     581             : #else /* WITH_MPI */
     582         256 :       normmax = norm
     583             : #endif /* WITH_MPI */
     584             : 
     585         768 :       if (myid .eq. 0) then
     586         512 :         print *," Maximum error of result: ", normmax
     587             :       endif
     588             : 
     589             : #ifdef DOUBLE_PRECISION_REAL
     590         384 :       if (normmax .gt. 5e-11_rk8 ) then
     591           0 :         status = 1
     592             :       endif
     593             : #else
     594         384 :       if (normmax .gt. 5e-3_rk4 ) then
     595           0 :         status = 1
     596             :       endif
     597             : #endif
     598             : 
     599             : #ifdef DOUBLE_PRECISION_COMPLEX
     600         384 :       if (normmax .gt. 5e-11_rk8 ) then
     601           0 :         status = 1
     602             :       endif
     603             : #else
     604         384 :       if (normmax .gt. 5e-3_rk4 ) then
     605           0 :         status = 1
     606             :       endif
     607             : #endif
     608        1536 :     end function
     609             : 
     610        3360 :     function check_correctness_eigenvalues_frank_&
     611             :     &MATH_DATATYPE&
     612             :     &_&
     613             :     &PRECISION&
     614        3360 :     & (na, ev, z, myid) result(status)
     615             :       use iso_c_binding
     616             :       implicit none
     617             : #include "../../src/general/precision_kinds.F90"
     618             : 
     619             :       integer                   :: status, i, j, myid
     620             :       integer, intent(in)       :: na
     621        6720 :       real(kind=rck)            :: ev_analytic(na), ev(na)
     622             :       MATH_DATATYPE(kind=rck)   :: z(:,:)
     623             : 
     624             : #if defined(DOUBLE_PRECISION_REAL) || defined(DOUBLE_PRECISION_COMPLEX)
     625             :       real(kind=rck), parameter :: pi = 3.141592653589793238462643383279_c_double
     626             : #else
     627             :       real(kind=rck), parameter :: pi = 3.1415926535897932_c_float
     628             : #endif
     629             :       real(kind=rck)            :: tmp, maxerr
     630             :       integer                   :: loctmp
     631        3360 :       status = 0
     632             : 
     633             :      ! analytic solution
     634      507360 :      do i = 1, na
     635      504000 :        j = na - i
     636             : #if defined(DOUBLE_PRECISION_REAL) || defined(DOUBLE_PRECISION_COMPLEX)
     637             :        ev_analytic(i) = pi * (2.0_c_double * real(j,kind=c_double) + 1.0_c_double) / &
     638      504000 :            (2.0_c_double * real(na,kind=c_double) + 1.0_c_double)
     639      504000 :        ev_analytic(i) = 0.5_c_double / (1.0_c_double - cos(ev_analytic(i)))
     640             : #else
     641             :        ev_analytic(i) = pi * (2.0_c_float * real(j,kind=c_float) + 1.0_c_float) / &
     642           0 :            (2.0_c_float * real(na,kind=c_float) + 1.0_c_float)
     643           0 :        ev_analytic(i) = 0.5_c_float / (1.0_c_float - cos(ev_analytic(i)))
     644             : #endif
     645             :      enddo
     646             : 
     647             :      ! sort analytic solution:
     648             : 
     649             :      ! this hack is neither elegant, nor optimized: for huge matrixes it might be expensive
     650             :      ! a proper sorting algorithmus might be implemented here
     651             : 
     652        3360 :      tmp    = minval(ev_analytic)
     653        3360 :      loctmp = minloc(ev_analytic, 1)
     654             : 
     655        3360 :      ev_analytic(loctmp) = ev_analytic(1)
     656        3360 :      ev_analytic(1) = tmp
     657      504000 :      do i=2, na
     658      500640 :        tmp = ev_analytic(i)
     659    38048640 :        do j= i, na
     660    37548000 :          if (ev_analytic(j) .lt. tmp) then
     661           0 :            tmp    = ev_analytic(j)
     662           0 :            loctmp = j
     663             :          endif
     664             :        enddo
     665      500640 :        ev_analytic(loctmp) = ev_analytic(i)
     666      500640 :        ev_analytic(i) = tmp
     667             :      enddo
     668             : 
     669             :      ! compute a simple error max of eigenvalues
     670        3360 :      maxerr = 0.0
     671        3360 :      maxerr = maxval( (ev(:) - ev_analytic(:))/ev_analytic(:) , 1)
     672             : 
     673             : #if defined(DOUBLE_PRECISION_REAL) || defined(DOUBLE_PRECISION_COMPLEX)
     674        3360 :      if (maxerr .gt. 8.e-13_c_double) then
     675             : #else
     676           0 :      if (maxerr .gt. 8.e-4_c_float) then
     677             : #endif
     678           0 :        status = 1
     679           0 :        if (myid .eq. 0) then
     680           0 :          print *,"Result of Frank matrix test: "
     681           0 :          print *,"Eigenvalues differ from analytic solution: maxerr = ",maxerr
     682             :        endif
     683             :      endif
     684        6720 :     end function
     685             : 
     686             : ! vim: syntax=fortran

Generated by: LCOV version 1.12