LCOV - code coverage report
Current view: top level - diagonalization - available_solvers.F90 (source / functions) Coverage Total Hit
Test: FLEUR test coverage Lines: 58.3 % 108 63
Test Date: 2025-11-24 04:36:21 Functions: 83.3 % 6 5

            Line data    Source code
       1              : !--------------------------------------------------------------------------------
       2              : ! Copyright (c) 2024 Peter Grünberg Institut, Forschungszentrum Jülich, Germany
       3              : ! This file is part of FLEUR and available as free software under the conditions
       4              : ! of the MIT license as expressed in the LICENSE file in more detail.
       5              : !--------------------------------------------------------------------------------
       6              : 
       7              : module m_available_solvers
       8              :    use m_types_solver
       9              :    use m_lapack
      10              :    use m_writeout
      11              :    use m_dummy_diag
      12              :    use m_scalapack
      13              :    use m_chase
      14              :    use m_elsi
      15              :    use m_magma
      16              :    use m_cuda_diag
      17              :    use m_elpa
      18              :    use m_nvlamath
      19              :    implicit none
      20              :    private
      21              :    integer :: first_real_solver = 4,num_solvers=11
      22              :    public:: t_solver, parallel_solver_available, select_solver, print_solver, list_solvers
      23              : 
      24              : contains
      25              : 
      26        12776 :    subroutine assign_solver(i,all_solvers)
      27              :       integer,INTENT(in) :: i
      28              :       CLASS(t_solver),allocatable,INTENT(OUT) :: all_solvers
      29        12874 :       select case (i)
      30              :       case(1)
      31           98 :          all_solvers=get_solver_stop()
      32              :       case(2)
      33           98 :          all_solvers=get_solver_dummy()
      34              :       case(3)
      35           98 :          all_solvers=get_solver_debugout()
      36              :       case(4)
      37         7181 :          all_solvers=get_solver_lapack()
      38              :       case(5)
      39         4755 :          all_solvers=get_solver_scalapack()
      40              :       case(6)
      41           91 :          all_solvers=get_solver_chase()
      42              :       case(7)
      43           91 :          all_solvers=get_solver_elsi()
      44              :       case(8)
      45           91 :          all_solvers=get_solver_magma()
      46              :       case(9)
      47           91 :          all_solvers=get_solver_cuda()
      48              :       case(10)
      49           91 :          all_solvers=get_solver_elpa()
      50              :       case(11)
      51           91 :          all_solvers=get_solver_nvlamath()
      52              :       case default
      53        12776 :          call judft_bug("Illegal request for solver")
      54              :       end select
      55        12776 :    end subroutine   
      56              : 
      57            7 :    function select_by_name(name)
      58              :       character(len=*),intent(in):: name
      59              :       CLASS(t_solver),allocatable :: select_by_name
      60              : 
      61              :       integer:: i
      62           35 :       DO i=1,num_solvers
      63           35 :          call assign_solver(i,select_by_name)
      64           35 :          if (trim(name)==trim(select_by_name%name)) return
      65              :       enddo 
      66            0 :       call judft_error("No Solver/transform could be selected:"//name)
      67            7 :    end function               
      68              : 
      69           91 :    logical function parallel_solver_available()
      70              :       integer ::i
      71          182 :       class(t_solver),allocatable::s
      72              : 
      73           91 :       parallel_solver_available = .false.
      74              :       !make an explit loop here
      75         1092 :       do i = 1, num_solvers
      76         1001 :          call assign_solver(i,s)
      77         2093 :          parallel_solver_available = parallel_solver_available .or. (s%available .and. s%parallel)
      78              :       end do
      79           91 :    end function parallel_solver_available
      80              : 
      81         7090 :    subroutine select_solver(parallel, gpu, single_precision,diag_solver,diag_transform)
      82              :       use m_juDFT
      83              :       logical, intent(IN)           :: parallel
      84              :       logical, intent(in), optional  :: single_precision, gpu
      85              :       class(t_solver), INTENT(OUT),allocatable  :: diag_solver,diag_transform
      86              : 
      87              :       logical :: use_single_precision, use_gpu, generalized, fit
      88              :       character(len=30):: name, trans
      89              :       integer :: i
      90              :    
      91         7090 :       use_single_precision = .false.
      92         7090 :       if (present(single_precision)) use_single_precision = single_precision
      93         7090 :       use_gpu = .false.
      94              : #ifdef _OPENACC
      95              :       use_gpu = .true.
      96              : #endif
      97         7090 :       if (present(gpu)) use_gpu = gpu
      98              : 
      99         7090 :       name = trim(juDFT_string_for_argument("-diag"))
     100         7090 :       if (len_trim(name) .gt. 0) then
     101              :          !solver was specified on command line
     102            7 :          if (index(name,"+") .gt. 0) then
     103              :             ! trensformation + standard solver
     104            0 :             trans = name(:index(name,"+")-1)
     105            0 :             name = name(index(name,"+") + 1:)
     106            0 :             diag_transform=select_by_name(trans)
     107              :          end if
     108              :          !check if "-sp" was given
     109            7 :          if (index(name,"-") .gt. 0) then
     110            0 :             use_single_precision = trim(name(index(name,"-") + 1:)) .eq. "sp"
     111            0 :             name = name(:index(name,"-")-1)
     112              :          end if
     113              :          !select solver from name
     114            7 :          diag_solver=select_by_name(name)
     115              :       else
     116              :          !defaults
     117        11740 :          do i = first_real_solver, num_solvers
     118        11740 :             call assign_solver(i,diag_solver)
     119        11740 :             fit = diag_solver%available
     120              :             !Check if solver fits the requirements
     121        11740 :             if (use_gpu) fit = fit .and. diag_solver%gpu
     122        11740 :             if (parallel) then
     123         9314 :                fit = fit .and. diag_solver%parallel
     124              :             else
     125         2426 :                fit = fit .and. diag_solver%serial
     126              :             end if
     127        11740 :             if (use_single_precision) fit = fit .and. diag_solver%single_precision
     128        23480 :             if (fit) exit
     129              :          end do
     130         7083 :          if (.not.fit) call judft_error("No default solver found.")
     131              :       end if
     132              : 
     133         7090 :       diag_solver%use_sp = use_single_precision
     134              :       
     135              :       !Check if a default tansformation must be selected as well
     136         7090 :       if ((.not. diag_solver%generalized .or. diag_solver%use_sp) .and. &
     137              :           .not. allocated(diag_transform)) &
     138              :          then
     139            0 :          do i = first_real_solver, num_solvers
     140            0 :             call assign_solver(i,diag_transform)
     141            0 :             fit = diag_transform%available .and. diag_transform%transform
     142              :             !Check if solver fits the requirements
     143            0 :             if (use_gpu) fit = fit .and. diag_transform%gpu
     144            0 :             if (parallel) then
     145            0 :                fit = fit .and. diag_transform%parallel
     146              :             else
     147            0 :                fit = fit .and. diag_transform%serial
     148              :             end if
     149            0 :             if (fit) exit
     150              :          end do
     151            0 :          if (.not.fit) call judft_error("No transform found")
     152              :       end if
     153              : 
     154              :       ! check if selected solvers are OK
     155         7090 :       generalized = .not. allocated(diag_transform)
     156         7090 :       if (.not. allocated(diag_transform)) then
     157              :          ! we use a generalized solver
     158         7090 :          if (.not. diag_solver%generalized) then 
     159            0 :             print *,diag_solver%name,diag_solver%generalized
     160            0 :             call judft_error("No generalized solver available")
     161              :          endif
     162         7090 :          if (parallel) then
     163         4664 :             if (.not. (diag_solver%parallel)) &
     164              :                call judft_error("No parallel solver available for your problem", &
     165            0 :                                 hint="You might have selected the wrong solver with the -diag option")
     166              :          else
     167         2426 :             if (.not. (diag_solver%serial)) &
     168              :                call judft_error("No serial solver available for your problem", &
     169            0 :                                 hint="You might have selected the wrong solver with the -diag option")
     170              :          end if
     171         7090 :          if (use_gpu) then
     172            0 :             if (.not. (diag_solver%gpu)) &
     173              :                call judft_warn("No GPU solver available for your problem", &
     174            0 :                                hint="You might have selected the wrong solver with the -diag option")
     175              :          end if
     176              :       else
     177              :          !we use a standard solver+transform
     178              :          if (.not. allocated(diag_transform) .and. diag_solver%standard) &
     179              :             call judft_error("No standard solver available or missing transform")
     180            0 :          if (parallel) then
     181            0 :             if (.not. (diag_solver%parallel .and. diag_transform%parallel)) &
     182              :                call judft_error("No parallel solver available for your problem", &
     183            0 :                                 hint="You might have selected the wrong solver with the -diag option")
     184              :          else
     185            0 :             if (.not. (diag_solver%serial .and. diag_transform%serial)) &
     186              :                call judft_error("No serial solver available for your problem", &
     187            0 :                                 hint="You might have selected the wrong solver with the -diag option")
     188              :          end if
     189            0 :          if (use_gpu) then
     190            0 :             if (.not. (diag_solver%gpu .and. diag_transform%gpu)) &
     191              :                call judft_warn("No GPU solver available for your problem", &
     192            0 :                                hint="You might have selected the wrong solver with the -diag option")
     193              :          end if
     194              :       end if
     195         7090 :    end subroutine select_solver
     196              : 
     197           67 :    function print_solver(parallel)
     198              :       logical, intent(IN):: parallel
     199              :       character(len=30):: print_solver
     200           67 :       class(t_solver), allocatable:: s,t
     201              : 
     202              :       call select_solver(parallel,diag_solver=s,diag_transform=t)
     203           67 :       print_solver = trim(s%name)
     204           67 :       if (s%use_sp) print_solver = trim(print_solver)//"-sp"
     205           67 :       if (allocated(t)) print_solver = t%name//'+'//trim(print_solver)
     206           67 :    end function
     207              : 
     208            0 :    subroutine list_solvers()
     209              :       integer:: i
     210            0 :       class(t_solver),allocatable::s
     211              : 
     212            0 :       write (*, '(a)') "Hints on choosing the diagonalization method (see the docu for more details):"
     213            0 :       write (*, '(a)') "  The `-diag` option takes a string as an argument that:"
     214            0 :       write (*, '(a)') "    Either simply specifies the solver used for the generalized eigenvalue problem (NAME_GEV):"
     215            0 :       write (*, '(a)') "      '-diag NAME_GEV'"
     216              :       write (*, '(a)') &
     217            0 :          "    Or the string combines (with '+') a solver of the standard problem (NAME_STD) with a transformation (NAME_TRANS):"
     218            0 :       write (*, '(a)') "      '-diag NAME_TRANS+NAME_STD'"
     219            0 :       write (*, '(a)') ""
     220            0 :       write (*, '(a)') "List of solvers/transforms:"
     221            0 :       write (*, '(a)') "   Name   available  serial  parallel  GEV  STD STD-SP  Transform  GPU: "
     222            0 :       do i = 1, num_solvers
     223            0 :          call assign_solver(i,s)
     224            0 :          write(*,'(a10,4x,l,7x,l,6x,l,6x,l,3x,l,2x,l,9x,l,6x,l)') s%name,s%available,s%serial,s%parallel,s%generalized,s%standard,s%single_precision,s%transform,s%gpu
     225              :       end do
     226            0 :       write (*, *)
     227            0 :    end subroutine
     228              : 
     229              : end module m_available_solvers
        

Generated by: LCOV version 2.0-1