mform/m_mform_eigensolver.f90
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | !> @brief Module that provides an interface to SLEPc for solving (generalized) eigenvalue problems | ||
| 2 | module m_mform_eigensolver | ||
| 3 | #include "petsc.fi" | ||
| 4 | use m_common, only: wp | ||
| 5 | use m_mform_basis, only: MFormSpace, size | ||
| 6 | use m_mform_constraint_global, only: MFormConstraint | ||
| 7 | use m_mform_matrix, only: AbstractMatrix | ||
| 8 | use m_mform_solver, only: get_constrained_petsc_matrix, SolverInitOptions, SolverInitTraits | ||
| 9 | |||
| 10 | implicit none | ||
| 11 | |||
| 12 | type, extends(SolverInitOptions) :: EigenInitOptions | ||
| 13 | !> Which part of the spectrum to compute (default: 'largest magnitude') | ||
| 14 | EPSWhich :: which = EPS_LARGEST_MAGNITUDE | ||
| 15 | !> The target value if 'which' is a target option (default: 0.0) | ||
| 16 | real(wp) :: target = 0.0_wp | ||
| 17 | !> The target interval if 'which' is 'all' (default: [0.0, 0.0]) | ||
| 18 | real(wp) :: target_interval(2) = [0.0_wp, 0.0_wp] | ||
| 19 | !> The type of eigensolver to use (default: 'krylovschur') | ||
| 20 | EPSType :: eps_type = EPSKRYLOVSCHUR | ||
| 21 | !> Whether 'which' is of target type (default: false) | ||
| 22 | logical :: which_is_target = .false. | ||
| 23 | contains | ||
| 24 | procedure :: init_from_traits => init_eigen_options_from_traits | ||
| 25 | end type EigenInitOptions | ||
| 26 | |||
| 27 | !> @brief Type that wraps SLEPc functionality for solving (generalized) eigenvalue problems | ||
| 28 | type :: EigenSolver | ||
| 29 | !> The SLEPc eigensolver context | ||
| 30 | EPS :: eps | ||
| 31 | |||
| 32 | !> The PETSc matrix (possibly constrained) | ||
| 33 | Mat :: matA, matB | ||
| 34 | |||
| 35 | !> The m-form space of the residual | ||
| 36 | type(MFormSpace) :: space_row | ||
| 37 | |||
| 38 | !> The optional constraint | ||
| 39 | type(MFormConstraint), allocatable :: constraint | ||
| 40 | |||
| 41 | integer :: nr_pairs | ||
| 42 | |||
| 43 | type(EigenInitOptions) :: options | ||
| 44 | contains | ||
| 45 | procedure :: init => EigenSolver_init | ||
| 46 | procedure :: solve => EigenSolver_solve | ||
| 47 | procedure :: get_eigenpair => EigenSolver_get_eigenpair | ||
| 48 | procedure :: get_eigenvalues => EigenSolver_get_eigenvalues | ||
| 49 | procedure :: destroy => EigenSolver_destroy | ||
| 50 | end type EigenSolver | ||
| 51 | |||
| 52 | interface EigenInitOptions | ||
| 53 | module procedure init_EigenInitOptions | ||
| 54 | end interface EigenInitOptions | ||
| 55 | contains | ||
| 56 | |||
| 57 | !> @brief Initialize an EigenInitOptions object | ||
| 58 | !> | ||
| 59 | !> @param ksp_type _(optional)_ The KSP type to use (default: auto-select based on traits) | ||
| 60 | !> @param pc_type _(optional)_ The PC type to use (default: auto-select based on traits) | ||
| 61 | !> @param hypre_type _(optional)_ The HYPRE preconditioner type to use (default: auto-select based on traits) | ||
| 62 | !> @param rtol _(optional)_ The relative tolerance (default: 1.e-10) | ||
| 63 | !> @param atol _(optional)_ The absolute tolerance (default: 1.e-20) | ||
| 64 | !> @param max_iter _(optional)_ The maximum number of iterations (default: size of the space) | ||
| 65 | !> @param verbosity _(optional)_ The verbosity level (default: 'warn on failure') | ||
| 66 | !> - 'warn never' | ||
| 67 | !> - 'warn on failure' | ||
| 68 | !> - 'warn always' | ||
| 69 | !> - 'error on failure' | ||
| 70 | !> @param which _(optional)_ Which part of the spectrum to compute. Possible values are: | ||
| 71 | !> @param which _(optional)_ Which part of the spectrum to compute. Possible values are: | ||
| 72 | !> - 'largest magnitude' or 'lm' (default) | ||
| 73 | !> - 'smallest magnitude' or 'sm' | ||
| 74 | !> - 'largest real' or 'lr' | ||
| 75 | !> - 'smallest real' or 'sr' | ||
| 76 | !> - 'largest imaginary' or 'li' | ||
| 77 | !> - 'smallest imaginary' or 'si' | ||
| 78 | !> - 'target magnitude' or 'tm' | ||
| 79 | !> - 'target real' or 'tr' | ||
| 80 | !> - 'target imaginary' or 'ti' | ||
| 81 | !> - 'target interval' or 'all' | ||
| 82 | !> @param target _(optional)_ The target value if 'which' is a target option | ||
| 83 | !> @param target_interval _(optional)_ The target interval if 'which' is 'all' | ||
| 84 | !> @param eps_type _(optional)_ The type of eigensolver to use (default: 'krylovschur'). Possible values are: | ||
| 85 | !> - 'power' | ||
| 86 | !> - 'subspace' | ||
| 87 | !> - 'arnoldi' | ||
| 88 | !> - 'lanczos' | ||
| 89 | !> - 'krylovschur' | ||
| 90 | !> - 'gd' | ||
| 91 | !> - 'jd' or 'jacobi davidson' | ||
| 92 | !> - 'rqcg' | ||
| 93 | !> - 'lobpcg' | ||
| 94 | !> - 'ciss' | ||
| 95 | !> - 'lyapii' | ||
| 96 | !> - 'lapack' | ||
| 97 | !> - 'arpack' | ||
| 98 | !> - 'blopex' | ||
| 99 | !> - 'primme' | ||
| 100 | !> - 'feast' | ||
| 101 | !> - 'scalapack' | ||
| 102 | !> - 'elpa' | ||
| 103 | !> - 'elemental' | ||
| 104 | !> - 'evsl' | ||
| 105 | !> - 'chase' | ||
| 106 | 22 | function init_EigenInitOptions(ksp_type, pc_type, hypre_type, rtol, atol, max_iter, verbosity, & | |
| 107 | which, target, target_interval, eps_type) result(options) | ||
| 108 | type(EigenInitOptions) :: options | ||
| 109 | character(*), optional, intent(in) :: ksp_type, pc_type, hypre_type | ||
| 110 | real(wp), optional, intent(in) :: rtol, atol | ||
| 111 | integer, optional, intent(in) :: max_iter | ||
| 112 | character(len=80), optional, intent(in) :: verbosity | ||
| 113 | character(*), optional, intent(in) :: which | ||
| 114 | real(wp), optional, intent(in) :: target | ||
| 115 | real(wp), optional, intent(in) :: target_interval(2) | ||
| 116 | character(*), optional, intent(in) :: eps_type | ||
| 117 | |||
| 118 | type(SolverInitOptions) :: base_options | ||
| 119 | |||
| 120 | base_options = SolverInitOptions(ksp_type=ksp_type, pc_type=pc_type, hypre_type=hypre_type, rtol=rtol, atol=atol, & | ||
| 121 |
3/6✓ Branch 7 → 8 taken 22 times.
✗ Branch 7 → 9 not taken.
✓ Branch 9 → 10 taken 22 times.
✗ Branch 9 → 11 not taken.
✓ Branch 11 → 12 taken 22 times.
✗ Branch 11 → 13 not taken.
|
88 | max_iter=max_iter, verbosity=verbosity) |
| 122 | 22 | options%ksp_type = base_options%ksp_type | |
| 123 | 22 | options%pc_type = base_options%pc_type | |
| 124 | 22 | options%hypre_type = base_options%hypre_type | |
| 125 | 22 | options%ilu_level = base_options%ilu_level | |
| 126 | 22 | options%rtol = base_options%rtol | |
| 127 | 22 | options%atol = base_options%atol | |
| 128 | 22 | options%max_iter = base_options%max_iter | |
| 129 | 22 | options%verbosity = base_options%verbosity | |
| 130 | #ifndef SLEPC_IS_LINKED | ||
| 131 | error stop "EigenInitOptions::init: SLEPc is not linked. Cannot use EigenInitOptions." | ||
| 132 | #else | ||
| 133 | options%which_is_target = .false. | ||
| 134 |
1/2✓ Branch 14 → 15 taken 22 times.
✗ Branch 14 → 30 not taken.
|
22 | if (present(which)) then |
| 135 | select case (which) | ||
| 136 | case ('largest magnitude', 'lm') | ||
| 137 | ✗ | options%which = EPS_LARGEST_MAGNITUDE | |
| 138 | case ('smallest magnitude', 'sm') | ||
| 139 | ✗ | options%which = EPS_SMALLEST_MAGNITUDE | |
| 140 | case ('largest real', 'lr') | ||
| 141 | ✗ | options%which = EPS_LARGEST_REAL | |
| 142 | case ('smallest real', 'sr') | ||
| 143 | 16 | options%which = EPS_SMALLEST_REAL | |
| 144 | case ('largest imaginary', 'li') | ||
| 145 | ✗ | options%which = EPS_LARGEST_IMAGINARY | |
| 146 | case ('smallest imaginary', 'si') | ||
| 147 | ✗ | options%which = EPS_SMALLEST_IMAGINARY | |
| 148 | case ('target magnitude', 'tm') | ||
| 149 | ✗ | options%which = EPS_TARGET_MAGNITUDE | |
| 150 | ✗ | options%which_is_target = .true. | |
| 151 | case ('target real', 'tr') | ||
| 152 | 6 | options%which = EPS_TARGET_REAL | |
| 153 | 6 | options%which_is_target = .true. | |
| 154 | case ('target imaginary', 'ti') | ||
| 155 | ✗ | options%which = EPS_TARGET_IMAGINARY | |
| 156 | ✗ | options%which_is_target = .true. | |
| 157 | case ('target interval', 'all') | ||
| 158 | ✗ | options%which = EPS_ALL | |
| 159 | case default | ||
| 160 | ✗ | write (*, '(A, A)') "Error: unknown option for 'which': ", which | |
| 161 |
2/11✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
✓ Branch 15 → 18 taken 16 times.
✗ Branch 15 → 19 not taken.
✗ Branch 15 → 20 not taken.
✗ Branch 15 → 21 not taken.
✓ Branch 15 → 22 taken 6 times.
✗ Branch 15 → 23 not taken.
✗ Branch 15 → 24 not taken.
✗ Branch 15 → 25 not taken.
✗ Branch 15 → 30 not taken.
|
22 | error stop |
| 162 | end select | ||
| 163 | else | ||
| 164 | options%which = EPS_LARGEST_MAGNITUDE | ||
| 165 | end if | ||
| 166 | |||
| 167 |
1/2✓ Branch 30 → 31 taken 22 times.
✗ Branch 30 → 56 not taken.
|
22 | if (present(eps_type)) then |
| 168 | ✗ | select case (eps_type) | |
| 169 | case ('power') | ||
| 170 | ✗ | options%eps_type = EPSPOWER | |
| 171 | case ('subspace') | ||
| 172 | ✗ | options%eps_type = EPSSUBSPACE | |
| 173 | case ('arnoldi') | ||
| 174 | 8 | options%eps_type = EPSARNOLDI | |
| 175 | case ('lanczos') | ||
| 176 | ✗ | options%eps_type = EPSLANCZOS | |
| 177 | case ('krylovschur') | ||
| 178 | 14 | options%eps_type = EPSKRYLOVSCHUR | |
| 179 | case ('gd') | ||
| 180 | ✗ | options%eps_type = EPSGD | |
| 181 | case ('jd', 'jacobi davidson') | ||
| 182 | ✗ | options%eps_type = EPSJD | |
| 183 | case ('rqcg') | ||
| 184 | ✗ | options%eps_type = EPSRQCG | |
| 185 | case ('lobpcg') | ||
| 186 | ✗ | options%eps_type = EPSLOBPCG | |
| 187 | case ('ciss') | ||
| 188 | ✗ | options%eps_type = EPSCISS | |
| 189 | case ('lyapii') | ||
| 190 | ✗ | options%eps_type = EPSLYAPII | |
| 191 | case ('lapack') | ||
| 192 | ✗ | options%eps_type = EPSLAPACK | |
| 193 | case ('arpack') | ||
| 194 | ✗ | options%eps_type = EPSARPACK | |
| 195 | case ('blopex') | ||
| 196 | ✗ | options%eps_type = EPSBLOPEX | |
| 197 | case ('primme') | ||
| 198 | ✗ | options%eps_type = EPSPRIMME | |
| 199 | case ('feast') | ||
| 200 | ✗ | options%eps_type = EPSFEAST | |
| 201 | case ('scalapack') | ||
| 202 | ✗ | options%eps_type = EPSSCALAPACK | |
| 203 | ! case ('elpa') | ||
| 204 | ! eps_type_ = EPSELPA | ||
| 205 | case ('elemental') | ||
| 206 | ✗ | options%eps_type = EPSELEMENTAL | |
| 207 | case ('evsl') | ||
| 208 | ✗ | options%eps_type = EPSEVSL | |
| 209 | ! case ('chase') | ||
| 210 | ! eps_type_ = EPSCHASE | ||
| 211 | case default | ||
| 212 | ✗ | write (*, '(A, A)') "Error: unknown option for 'eps_type': ", eps_type | |
| 213 |
2/20✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
✓ Branch 31 → 34 taken 8 times.
✗ Branch 31 → 35 not taken.
✓ Branch 31 → 36 taken 14 times.
✗ Branch 31 → 37 not taken.
✗ Branch 31 → 38 not taken.
✗ Branch 31 → 39 not taken.
✗ Branch 31 → 40 not taken.
✗ Branch 31 → 41 not taken.
✗ Branch 31 → 42 not taken.
✗ Branch 31 → 43 not taken.
✗ Branch 31 → 44 not taken.
✗ Branch 31 → 45 not taken.
✗ Branch 31 → 46 not taken.
✗ Branch 31 → 47 not taken.
✗ Branch 31 → 48 not taken.
✗ Branch 31 → 49 not taken.
✗ Branch 31 → 50 not taken.
✗ Branch 31 → 51 not taken.
|
22 | error stop |
| 214 | end select | ||
| 215 | else | ||
| 216 | ✗ | options%eps_type = EPSKRYLOVSCHUR | |
| 217 | end if | ||
| 218 | |||
| 219 |
2/2✓ Branch 57 → 58 taken 6 times.
✓ Branch 57 → 63 taken 16 times.
|
22 | if (present(target)) then |
| 220 | 6 | options%target = target | |
| 221 |
1/2✗ Branch 58 → 59 not taken.
✓ Branch 58 → 63 taken 6 times.
|
6 | if (.not. options%which_is_target) then |
| 222 | ✗ | write (*, '(A)') "EigenSolver::init Warning: 'target' specified but 'which' is not a target option" | |
| 223 | end if | ||
| 224 | else | ||
| 225 | options%target = 0.0_wp | ||
| 226 | end if | ||
| 227 | |||
| 228 |
1/2✗ Branch 63 → 64 not taken.
✓ Branch 63 → 71 taken 22 times.
|
22 | if (present(target_interval)) then |
| 229 | ✗ | options%target_interval = target_interval | |
| 230 | ✗ | if (options%which /= EPS_ALL) then | |
| 231 | ✗ | write (*, '(A)') "EigenSolver::init Warning: 'target_interval' specified but 'which' is not 'all'" | |
| 232 | end if | ||
| 233 | else | ||
| 234 |
2/2✓ Branch 71 → 72 taken 44 times.
✓ Branch 71 → 73 taken 22 times.
|
66 | options%target_interval = [0.0_wp, 0.0_wp] |
| 235 | end if | ||
| 236 | #endif | ||
| 237 |
3/4✓ Branch 3 → 4 taken 44 times.
✓ Branch 3 → 5 taken 22 times.
✓ Branch 5 → 6 taken 22 times.
✗ Branch 5 → 7 not taken.
|
66 | end function init_EigenInitOptions |
| 238 | |||
| 239 | !> @brief Select solver options for eigenvalue problems, favouring direct solvers (MUMPS) | ||
| 240 | !> | ||
| 241 | !> Eigenvalue solvers require highly accurate linear solves inside the spectral | ||
| 242 | !> transform. Iterative methods with standard preconditioners often lack the | ||
| 243 | !> accuracy needed for convergence of multiple eigenpairs. This override | ||
| 244 | !> defaults to a direct solver (PREONLY + Cholesky/LU with MUMPS) which works | ||
| 245 | !> both in serial and parallel. | ||
| 246 | !> | ||
| 247 | !> @param this The EigenInitOptions object | ||
| 248 | !> @param traits The solver traits derived from matrix properties | ||
| 249 | 22 | subroutine init_eigen_options_from_traits(this, traits) | |
| 250 | class(EigenInitOptions), intent(inout) :: this | ||
| 251 | type(SolverInitTraits), intent(in) :: traits | ||
| 252 | |||
| 253 |
1/2✓ Branch 2 → 3 taken 22 times.
✗ Branch 2 → 4 not taken.
|
22 | if (len_trim(this%ksp_type) == 0) then |
| 254 | 22 | this%ksp_type = 'preonly' | |
| 255 | end if | ||
| 256 | |||
| 257 |
1/2✓ Branch 4 → 5 taken 22 times.
✗ Branch 4 → 9 not taken.
|
22 | if (len_trim(this%pc_type) == 0) then |
| 258 |
2/4✓ Branch 5 → 6 taken 22 times.
✗ Branch 5 → 8 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 22 times.
|
22 | if (traits%is_symmetric .and. traits%is_spd) then |
| 259 | ✗ | this%pc_type = 'cholesky' | |
| 260 | else | ||
| 261 | 22 | this%pc_type = 'lu' | |
| 262 | end if | ||
| 263 | end if | ||
| 264 | 22 | end subroutine init_eigen_options_from_traits | |
| 265 | |||
| 266 | !> @brief Initialize the eigensolver | ||
| 267 | !> | ||
| 268 | !> @param this The EigenSolver object | ||
| 269 | !> @param amat The matrix A in the eigenvalue problem: $A x = \lambda x$ | ||
| 270 | !> @param bmat _(optional)_ The matrix B in the eigenvalue problem: $A x = \lambda B x$ | ||
| 271 | !> @param[in] constraint1 _(optional)_ An optional constraint to be applied to the solution | ||
| 272 | !> @param[in] constraint2 _(optional)_ An optional constraint to be applied to the solution | ||
| 273 | !> @param[in] constraint3 _(optional)_ An optional constraint to be applied to the solution | ||
| 274 | !> @param[in] coord_transform _(optional)_ The coordinate transformation associated with the m-form spaces | ||
| 275 | !> @param options _(optional)_ The options for initializing the eigensolver (default: auto-select based on traits) | ||
| 276 | 22 | subroutine EigenSolver_init(this, amat, bmat, constraint1, constraint2, constraint3, coord_transform, options) | |
| 277 | use m_mform_constraint_abstract, only: MFormConstraintLocal | ||
| 278 | use m_coord_transform_abstract, only: CoordTransformAbstract | ||
| 279 | implicit none | ||
| 280 | |||
| 281 | class(EigenSolver), intent(inout) :: this | ||
| 282 | class(AbstractMatrix), intent(in) :: amat | ||
| 283 | class(AbstractMatrix), optional, intent(in) :: bmat | ||
| 284 | class(MFormConstraintLocal), optional, intent(in) :: constraint1, constraint2, constraint3 | ||
| 285 | class(CoordTransformAbstract), optional, intent(in) :: coord_transform | ||
| 286 | type(EigenInitOptions), optional, intent(in) :: options | ||
| 287 | |||
| 288 | integer :: ierr | ||
| 289 | EPSProblemType :: eps_problem_type | ||
| 290 | type(SolverInitTraits) :: traits | ||
| 291 | ST :: st | ||
| 292 | KSP :: ksp | ||
| 293 | PC :: pc | ||
| 294 | |||
| 295 | #ifndef SLEPC_IS_LINKED | ||
| 296 | error stop "EigenSolver::init: SLEPc is not linked. Cannot use EigenSolver." | ||
| 297 | #else | ||
| 298 | 22 | call this%destroy() | |
| 299 | |||
| 300 |
1/2✓ Branch 3 → 4 taken 22 times.
✗ Branch 3 → 5 not taken.
|
22 | if (present(options)) this%options = options |
| 301 | |||
| 302 |
5/12✓ Branch 5 → 6 taken 14 times.
✓ Branch 5 → 7 taken 8 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 11 taken 14 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 8 times.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 11 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 33 taken 8 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 33 not taken.
|
22 | if (present(constraint1) .or. present(constraint2) .or. present(constraint3)) then |
| 303 |
4/6✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 14 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 14 times.
✓ Branch 16 → 17 taken 70 times.
✓ Branch 16 → 18 taken 14 times.
|
84 | allocate (this%constraint) |
| 304 | 14 | call this%constraint%init(amat%space_col) | |
| 305 | |||
| 306 |
2/4✓ Branch 19 → 20 taken 14 times.
✗ Branch 19 → 23 not taken.
✓ Branch 20 → 21 taken 14 times.
✗ Branch 20 → 23 not taken.
|
14 | if (present(constraint1)) call this%constraint%insert(constraint1, coord_transform=coord_transform) |
| 307 |
2/4✓ Branch 23 → 24 taken 14 times.
✗ Branch 23 → 27 not taken.
✓ Branch 24 → 25 taken 14 times.
✗ Branch 24 → 27 not taken.
|
14 | if (present(constraint2)) call this%constraint%insert(constraint2, coord_transform=coord_transform) |
| 308 |
1/4✗ Branch 27 → 28 not taken.
✓ Branch 27 → 31 taken 14 times.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 31 not taken.
|
14 | if (present(constraint3)) call this%constraint%insert(constraint3, coord_transform=coord_transform) |
| 309 | |||
| 310 | 14 | call this%constraint%assemble() | |
| 311 | end if | ||
| 312 | |||
| 313 |
2/4✓ Branch 33 → 34 taken 22 times.
✗ Branch 33 → 44 not taken.
✓ Branch 34 → 35 taken 22 times.
✗ Branch 34 → 44 not taken.
|
22 | if (present(bmat)) then |
| 314 |
1/2✗ Branch 35 → 36 not taken.
✓ Branch 35 → 40 taken 22 times.
|
22 | if (size(amat%space_row) /= size(bmat%space_row)) then |
| 315 | ✗ | write (*, '(A)') "Error: EigenSolver::init: the row space of A and B must have the same size" | |
| 316 | ✗ | error stop | |
| 317 | end if | ||
| 318 |
2/4✓ Branch 40 → 41 taken 22 times.
✗ Branch 40 → 43 not taken.
✓ Branch 41 → 42 taken 22 times.
✗ Branch 41 → 43 not taken.
|
22 | if (amat%is_symmetric .and. bmat%is_symmetric) then |
| 319 | 22 | eps_problem_type = EPS_GHEP | |
| 320 | else | ||
| 321 | ✗ | eps_problem_type = EPS_GNHEP | |
| 322 | end if | ||
| 323 | else | ||
| 324 | ✗ | if (amat%is_symmetric) then | |
| 325 | ✗ | eps_problem_type = EPS_HEP | |
| 326 | else | ||
| 327 | ✗ | eps_problem_type = EPS_NHEP | |
| 328 | end if | ||
| 329 | end if | ||
| 330 | |||
| 331 | #endif | ||
| 332 | |||
| 333 |
5/8✓ Branch 47 → 48 taken 22 times.
✗ Branch 47 → 51 not taken.
✓ Branch 48 → 49 taken 22 times.
✗ Branch 48 → 50 not taken.
✓ Branch 51 → 52 taken 22 times.
✗ Branch 51 → 54 not taken.
✓ Branch 52 → 53 taken 19 times.
✓ Branch 52 → 54 taken 3 times.
|
22 | this%space_row = amat%space_row |
| 334 |
1/2✗ Branch 55 → 56 not taken.
✓ Branch 55 → 58 taken 22 times.
|
22 | SlepcCall(EPSCreate(this%space_row%tp_spaces(1)%domain%comm, this%eps, ierr)) |
| 335 | |||
| 336 |
1/2✗ Branch 59 → 60 not taken.
✓ Branch 59 → 62 taken 22 times.
|
22 | SlepcCall(EPSSetType(this%eps, this%options%eps_type, ierr)) |
| 337 |
1/2✗ Branch 63 → 64 not taken.
✓ Branch 63 → 66 taken 22 times.
|
22 | SlepcCall(EPSSetProblemType(this%eps, eps_problem_type, ierr)) |
| 338 | |||
| 339 |
2/2✓ Branch 66 → 67 taken 8 times.
✓ Branch 66 → 70 taken 14 times.
|
22 | if (.not. allocated(this%constraint)) then |
| 340 | ! NOTE a copy is required because the destructor of amat will destroy the matrix | ||
| 341 |
1/2✗ Branch 68 → 69 not taken.
✓ Branch 68 → 73 taken 8 times.
|
8 | PetscCall(MatConvert(amat%mat, "same", MAT_INITIAL_MATRIX, this%matA, ierr)) |
| 342 | else | ||
| 343 | |||
| 344 | 14 | call get_constrained_petsc_matrix(this%matA, amat%mat, this%constraint, coeff=amat%constraint_coeff()) | |
| 345 | end if | ||
| 346 |
2/4✓ Branch 73 → 74 taken 22 times.
✗ Branch 73 → 75 not taken.
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 79 taken 22 times.
|
22 | if (.not. present(bmat)) then |
| 347 | ✗ | SlepcCall(EPSSetOperators(this%eps, this%matA, PETSC_NULL_MAT, ierr)) | |
| 348 | else | ||
| 349 |
2/2✓ Branch 79 → 80 taken 8 times.
✓ Branch 79 → 83 taken 14 times.
|
22 | if (.not. allocated(this%constraint)) then |
| 350 | ! NOTE a copy is required because the destructor of amat will destroy the matrix | ||
| 351 |
1/2✗ Branch 81 → 82 not taken.
✓ Branch 81 → 86 taken 8 times.
|
8 | PetscCall(MatConvert(bmat%mat, "same", MAT_INITIAL_MATRIX, this%matB, ierr)) |
| 352 | else | ||
| 353 | |||
| 354 | 14 | call get_constrained_petsc_matrix(this%matB, bmat%mat, this%constraint, coeff=bmat%constraint_coeff()) | |
| 355 | end if | ||
| 356 | |||
| 357 |
1/2✗ Branch 87 → 88 not taken.
✓ Branch 87 → 90 taken 22 times.
|
22 | SlepcCall(EPSSetOperators(this%eps, this%matA, this%matB, ierr)) |
| 358 | end if | ||
| 359 | |||
| 360 |
1/2✗ Branch 91 → 92 not taken.
✓ Branch 91 → 94 taken 22 times.
|
22 | SlepcCall(EPSSetWhichEigenpairs(this%eps, this%options%which, ierr)) |
| 361 |
2/2✓ Branch 94 → 95 taken 6 times.
✓ Branch 94 → 99 taken 16 times.
|
22 | if (this%options%which_is_target) then |
| 362 |
1/2✗ Branch 96 → 97 not taken.
✓ Branch 96 → 99 taken 6 times.
|
6 | SlepcCall(EPSSetTarget(this%eps, this%options%target, ierr)) |
| 363 | end if | ||
| 364 | |||
| 365 |
1/2✗ Branch 99 → 100 not taken.
✓ Branch 99 → 104 taken 22 times.
|
22 | if (this%options%which == EPS_ALL) then |
| 366 | ✗ | SlepcCall(EPSSetInterval(this%eps, this%options%target_interval(1), this%options%target_interval(2), ierr)) | |
| 367 | end if | ||
| 368 | |||
| 369 | |||
| 370 | ! Build traits from matrix properties for automatic solver selection | ||
| 371 | 22 | traits%is_symmetric = amat%is_symmetric | |
| 372 | ! The shifted operator (A - sigma*B) is generally indefinite, so not SPD | ||
| 373 | traits%is_spd = .false. | ||
| 374 | 22 | traits%is_parallel = amat%space_row%tp_spaces(1)%domain%nr_ranks > 1 | |
| 375 | traits%is_diffdiff = .false. ! Irrelevant | ||
| 376 | 22 | traits%m_form = amat%space_col%m | |
| 377 | 22 | traits%allow_ams = .false. | |
| 378 | |||
| 379 | 22 | call this%options%init_from_traits(traits) | |
| 380 | |||
| 381 | ! Configure the Spectral Transform (ST) and its linear solver (KSP) | ||
| 382 |
1/2✗ Branch 106 → 107 not taken.
✓ Branch 106 → 109 taken 22 times.
|
22 | SlepcCall(EPSGetST(this%eps, st, ierr)) |
| 383 | |||
| 384 |
3/4✓ Branch 109 → 110 taken 16 times.
✓ Branch 109 → 111 taken 6 times.
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 115 taken 16 times.
|
22 | if (this%options%which_is_target .or. this%options%which == EPS_ALL) then |
| 385 | ! Target-based eigenvalue problems require shift-and-invert | ||
| 386 |
1/2✗ Branch 112 → 113 not taken.
✓ Branch 112 → 115 taken 6 times.
|
6 | SlepcCall(STSetType(st, STSINVERT, ierr)) |
| 387 | end if | ||
| 388 | |||
| 389 |
1/2✗ Branch 116 → 117 not taken.
✓ Branch 116 → 119 taken 22 times.
|
22 | SlepcCall(STGetKSP(st, ksp, ierr)) |
| 390 |
1/2✗ Branch 120 → 121 not taken.
✓ Branch 120 → 122 taken 22 times.
|
22 | PetscCall(KSPSetType(ksp, this%options%ksp_type, ierr)) |
| 391 |
1/2✗ Branch 123 → 124 not taken.
✓ Branch 123 → 125 taken 22 times.
|
22 | PetscCall(KSPGetPC(ksp, pc, ierr)) |
| 392 |
2/4✓ Branch 125 → 126 taken 22 times.
✗ Branch 125 → 127 not taken.
✓ Branch 126 → 127 taken 22 times.
✗ Branch 126 → 134 not taken.
|
22 | if (this%options%pc_type == 'cholesky' .or. this%options%pc_type == 'lu') then |
| 393 |
1/2✗ Branch 128 → 129 not taken.
✓ Branch 128 → 130 taken 22 times.
|
22 | PetscCall(PCSetType(pc, this%options%pc_type, ierr)) |
| 394 |
1/2✗ Branch 130 → 131 not taken.
✓ Branch 130 → 143 taken 22 times.
|
22 | if (traits%is_parallel) then |
| 395 | ✗ | PetscCall(PCFactorSetMatSolverType(pc, MATSOLVERMUMPS, ierr)) | |
| 396 | end if | ||
| 397 | ✗ | else if (.not. (this%options%pc_type == 'hypre' .and. this%options%hypre_type == 'ilu')) then | |
| 398 | ✗ | PetscCall(PCSetType(pc, this%options%pc_type, ierr)) | |
| 399 | ✗ | if (this%options%pc_type == 'hypre') then | |
| 400 | ✗ | PetscCall(PCHYPRESetType(pc, this%options%hypre_type, ierr)) | |
| 401 | end if | ||
| 402 | end if | ||
| 403 | |||
| 404 | ! Allow command-line overrides after programmatic configuration | ||
| 405 |
1/2✗ Branch 144 → 145 not taken.
✓ Branch 144 → 147 taken 22 times.
|
22 | SlepcCall(EPSSetFromOptions(this%eps, ierr)) |
| 406 | 22 | end subroutine EigenSolver_init | |
| 407 | |||
| 408 | !> @brief Solve the eigenvalue problem | ||
| 409 | !> | ||
| 410 | !> @param this The EigenSolver object | ||
| 411 | !> @param rtol _(optional)_ The relative tolerance (default: 1.e-8) | ||
| 412 | !> @param max_iter _(optional)_ The maximum number of iterations (default: size of the space) | ||
| 413 | !> @param nr_pairs _(optional)_ The number of eigenpairs to compute (default: 6) | ||
| 414 | !> @param verbosity _(optional)_ The verbosity level (default: VERBOSITY_WARN_ON_FAILURE) | ||
| 415 | !> - VERBOSITY_WARN_NEVER | ||
| 416 | !> - VERBOSITY_WARN_ON_FAILURE | ||
| 417 | !> - VERBOSITY_WARN_ALWAYS | ||
| 418 | !> - VERBOSITY_ERROR_ON_FAILURE | ||
| 419 | 22 | subroutine EigenSolver_solve(this, rtol, max_iter, nr_pairs, verbosity) | |
| 420 | use m_common, only: wp, VERBOSITY_WARN_NEVER, VERBOSITY_WARN_ON_FAILURE, VERBOSITY_WARN_ALWAYS, VERBOSITY_ERROR_ON_FAILURE | ||
| 421 | implicit none | ||
| 422 | |||
| 423 | class(EigenSolver), intent(inout) :: this | ||
| 424 | integer :: ierr | ||
| 425 | real(wp), optional, intent(in) :: rtol | ||
| 426 | integer, optional, intent(in) :: max_iter | ||
| 427 | integer, optional, intent(in) :: nr_pairs | ||
| 428 | integer, optional, intent(in) :: verbosity | ||
| 429 | |||
| 430 | real(wp) :: rtol_ | ||
| 431 | integer :: max_iter_ | ||
| 432 | integer :: nr_pairs_ | ||
| 433 | integer :: verbosity_ | ||
| 434 | |||
| 435 |
1/2✓ Branch 2 → 3 taken 22 times.
✗ Branch 2 → 4 not taken.
|
22 | if (present(rtol)) then |
| 436 | 22 | rtol_ = rtol | |
| 437 | else | ||
| 438 | ✗ | rtol_ = 1.e-8_wp | |
| 439 | end if | ||
| 440 | |||
| 441 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 22 times.
|
22 | if (present(max_iter)) then |
| 442 | ✗ | max_iter_ = max_iter | |
| 443 | else | ||
| 444 | 22 | max_iter_ = size(this%space_row) | |
| 445 | end if | ||
| 446 | |||
| 447 |
1/2✓ Branch 8 → 9 taken 22 times.
✗ Branch 8 → 10 not taken.
|
22 | if (present(nr_pairs)) then |
| 448 | 22 | nr_pairs_ = nr_pairs | |
| 449 | else | ||
| 450 | ✗ | nr_pairs_ = min(6, size(this%space_row)) | |
| 451 | end if | ||
| 452 | |||
| 453 | 22 | if (this%space_row%tp_spaces(1)%domain%my_rank > 0) then | |
| 454 | verbosity_ = VERBOSITY_WARN_NEVER | ||
| 455 | else | ||
| 456 | if (present(verbosity)) then | ||
| 457 | verbosity_ = verbosity | ||
| 458 | else | ||
| 459 | verbosity_ = VERBOSITY_WARN_ON_FAILURE | ||
| 460 | end if | ||
| 461 | end if | ||
| 462 | |||
| 463 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 15 taken 22 times.
|
22 | SlepcCall(EPSSetTolerances(this%eps, rtol_, max_iter_, ierr)) |
| 464 |
1/2✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 22 times.
|
22 | SlepcCall(EPSSetDimensions(this%eps, nr_pairs_, PETSC_DECIDE, PETSC_DECIDE, ierr)) |
| 465 | |||
| 466 |
1/2✗ Branch 20 → 21 not taken.
✓ Branch 20 → 23 taken 22 times.
|
22 | SlepcCall(EPSSolve(this%eps, ierr)) |
| 467 |
1/2✗ Branch 24 → 25 not taken.
✓ Branch 24 → 27 taken 22 times.
|
22 | SlepcCall(EPSGetConverged(this%eps, this%nr_pairs, ierr)) |
| 468 | ! TODO check for convergence | ||
| 469 | 22 | end subroutine EigenSolver_solve | |
| 470 | |||
| 471 | !> @brief Get an eigenpair | ||
| 472 | !> | ||
| 473 | !> @param this The EigenSolver object | ||
| 474 | !> @param index The index of the eigenpair to get (1-based) | ||
| 475 | !> @param val_r The real part of the eigenvalue | ||
| 476 | !> @param fun_r The real part of the eigenfunction | ||
| 477 | !> @param val_i _(optional)_ The imaginary part of the eigenvalue | ||
| 478 | !> @param fun_i _(optional)_ The imaginary part of the eigenfunction | ||
| 479 | !> @param err_est _(optional)_ The error estimate for the eigenpair | ||
| 480 | ✗ | subroutine EigenSolver_get_eigenpair(this, index, val_r, fun_r, val_i, fun_i, err_est) | |
| 481 | use m_mform_constraint_global, only: CONSTRAINT_EXTRACTION | ||
| 482 | use m_mform_basis, only: MFormFun | ||
| 483 | implicit none | ||
| 484 | |||
| 485 | class(EigenSolver), intent(in) :: this | ||
| 486 | integer, intent(in) :: index | ||
| 487 | real(wp), intent(out) :: val_r | ||
| 488 | real(wp), optional, intent(out) :: val_i | ||
| 489 | type(MFormFun), intent(out) :: fun_r | ||
| 490 | type(MFormFun), optional, intent(out) :: fun_i | ||
| 491 | real(wp), optional, intent(out) :: err_est | ||
| 492 | |||
| 493 | Vec :: vec_r, vec_i | ||
| 494 | Vec :: vec_r_proj, vec_i_proj | ||
| 495 | integer :: ierr | ||
| 496 | |||
| 497 | ✗ | PetscCall(MatCreateVecs(this%matA, vec_r_proj, PETSC_NULL_VEC, ierr)) | |
| 498 | ✗ | if (present(fun_i)) then | |
| 499 | ✗ | PetscCall(VecDuplicate(vec_r_proj, vec_i_proj, ierr)) | |
| 500 | end if | ||
| 501 | |||
| 502 | if (present(fun_i)) then | ||
| 503 | ✗ | SlepcCall(EPSGetEigenpair(this%eps, index - 1, val_r, val_i, vec_r_proj, vec_i_proj, ierr)) | |
| 504 | else | ||
| 505 | ✗ | SlepcCall(EPSGetEigenpair(this%eps, index - 1, val_r, PETSC_NULL_SCALAR, vec_r_proj, PETSC_NULL_VEC, ierr)) | |
| 506 | end if | ||
| 507 | |||
| 508 | ✗ | if (allocated(this%constraint)) then | |
| 509 | ✗ | if (this%constraint%mode == CONSTRAINT_EXTRACTION) then | |
| 510 | ✗ | PetscCall(VecCreate(this%space_row%tp_spaces(1)%domain%comm, vec_r, ierr)) | |
| 511 | ✗ | PetscCall(VecSetSizes(vec_r, size(this%space_row, my_rank=.true.), size(this%space_row), ierr)) | |
| 512 | ✗ | PetscCall(VecSetFromOptions(vec_r, ierr)) | |
| 513 | ✗ | PetscCall(MatMult(this%constraint%mat, vec_r_proj, vec_r, ierr)) | |
| 514 | |||
| 515 | ✗ | if (present(fun_i)) then | |
| 516 | ✗ | PetscCall(VecDuplicate(vec_r, vec_i, ierr)) | |
| 517 | ✗ | PetscCall(MatMult(this%constraint%mat, vec_i_proj, vec_i, ierr)) | |
| 518 | end if | ||
| 519 | else | ||
| 520 | ✗ | PetscCall(VecCopy(vec_r_proj, vec_r, ierr)) | |
| 521 | ✗ | if (present(fun_i)) then | |
| 522 | ✗ | PetscCall(VecCopy(vec_i_proj, vec_i, ierr)) | |
| 523 | end if | ||
| 524 | end if | ||
| 525 | else | ||
| 526 | ✗ | vec_r = vec_r_proj | |
| 527 | ✗ | if (present(fun_i)) then | |
| 528 | ✗ | vec_i = vec_i_proj | |
| 529 | end if | ||
| 530 | end if | ||
| 531 | |||
| 532 | ✗ | call fun_r%init(this%space_row, vec=vec_r) | |
| 533 | ✗ | PetscCall(VecDestroy(vec_r, ierr)) | |
| 534 | ✗ | if (allocated(this%constraint)) then | |
| 535 | ✗ | PetscCall(VecDestroy(vec_r_proj, ierr)) | |
| 536 | end if | ||
| 537 | |||
| 538 | ✗ | if (present(fun_i)) then | |
| 539 | ✗ | call fun_i%init(this%space_row, vec=vec_i) | |
| 540 | ✗ | PetscCall(VecDestroy(vec_i, ierr)) | |
| 541 | ✗ | if (allocated(this%constraint)) then | |
| 542 | ✗ | PetscCall(VecDestroy(vec_i_proj, ierr)) | |
| 543 | end if | ||
| 544 | end if | ||
| 545 | |||
| 546 | ✗ | if (present(err_est)) then | |
| 547 | ✗ | SlepcCall(EPSGetErrorEstimate(this%eps, index - 1, err_est, ierr)) | |
| 548 | end if | ||
| 549 | |||
| 550 | ✗ | end subroutine EigenSolver_get_eigenpair | |
| 551 | |||
| 552 | !> @brief Get all computed eigenvalues | ||
| 553 | !> | ||
| 554 | !> @param this The EigenSolver object | ||
| 555 | !> @param vals_r The real parts of the eigenvalues | ||
| 556 | !> @param vals_i _(optional)_ The imaginary parts of the eigenvalues | ||
| 557 | 22 | subroutine EigenSolver_get_eigenvalues(this, vals_r, vals_i) | |
| 558 | implicit none | ||
| 559 | |||
| 560 | class(EigenSolver), intent(in) :: this | ||
| 561 | real(wp), allocatable, intent(out) :: vals_r(:) | ||
| 562 | real(wp), optional, allocatable, intent(out) :: vals_i(:) | ||
| 563 | |||
| 564 | integer :: i, ierr | ||
| 565 | |||
| 566 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 14 taken 22 times.
|
22 | if (this%nr_pairs <= 0) then |
| 567 | ✗ | allocate (vals_r(0)) | |
| 568 | ✗ | if (present(vals_i)) allocate (vals_i(0)) | |
| 569 | ✗ | return | |
| 570 | end if | ||
| 571 | |||
| 572 |
6/12✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 22 times.
✓ Branch 16 → 15 taken 22 times.
✗ Branch 16 → 17 not taken.
✓ Branch 17 → 18 taken 22 times.
✗ Branch 17 → 19 not taken.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 22 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 22 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 22 times.
|
66 | allocate (vals_r(this%nr_pairs)) |
| 573 |
6/12✓ Branch 25 → 26 taken 22 times.
✗ Branch 25 → 42 not taken.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 22 times.
✓ Branch 28 → 27 taken 22 times.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 22 times.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 22 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 22 times.
|
44 | if (present(vals_i)) allocate (vals_i(this%nr_pairs)) |
| 574 | |||
| 575 | if (present(vals_i)) then | ||
| 576 |
2/2✓ Branch 36 → 37 taken 295 times.
✓ Branch 36 → 49 taken 22 times.
|
317 | do i = 1, this%nr_pairs |
| 577 |
1/2✗ Branch 38 → 39 not taken.
✓ Branch 38 → 41 taken 295 times.
|
317 | SlepcCall(EPSGetEigenvalue(this%eps, i - 1, vals_r(i), vals_i(i), ierr)) |
| 578 | end do | ||
| 579 | else | ||
| 580 | ✗ | do i = 1, this%nr_pairs | |
| 581 | ✗ | SlepcCall(EPSGetEigenvalue(this%eps, i - 1, vals_r(i), PETSC_NULL_SCALAR, ierr)) | |
| 582 | end do | ||
| 583 | end if | ||
| 584 | |||
| 585 | end subroutine EigenSolver_get_eigenvalues | ||
| 586 | |||
| 587 | !> @brief Destroy the eigensolver and free associated resources | ||
| 588 | !> | ||
| 589 | !> @param this The EigenSolver object | ||
| 590 | 25 | subroutine EigenSolver_destroy(this) | |
| 591 | implicit none | ||
| 592 | |||
| 593 | class(EigenSolver), intent(inout) :: this | ||
| 594 | integer :: ierr | ||
| 595 | |||
| 596 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 25 times.
|
25 | SlepcCall(EPSDestroy(this%eps, ierr)) |
| 597 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 25 times.
|
25 | PetscCall(MatDestroy(this%matA, ierr)) |
| 598 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 25 times.
|
25 | PetscCall(MatDestroy(this%matB, ierr)) |
| 599 |
2/2✓ Branch 12 → 13 taken 14 times.
✓ Branch 12 → 87 taken 11 times.
|
25 | if (allocated(this%constraint)) then |
| 600 | 14 | call this%constraint%destroy() | |
| 601 |
12/68✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 14 times.
✓ Branch 16 → 17 taken 14 times.
✗ Branch 16 → 18 not taken.
✓ Branch 19 → 20 taken 70 times.
✓ Branch 19 → 63 taken 14 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 23 taken 70 times.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 62 taken 70 times.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 39 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 38 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 50 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 49 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 61 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 60 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 55 not taken.
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 57 not taken.
✗ Branch 57 → 58 not taken.
✗ Branch 57 → 59 not taken.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 65 taken 14 times.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 14 times.
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 69 taken 14 times.
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 71 taken 14 times.
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 14 times.
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 86 taken 14 times.
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 85 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 78 not taken.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
|
98 | deallocate (this%constraint) |
| 602 | end if | ||
| 603 | |||
| 604 | end subroutine EigenSolver_destroy | ||
| 605 | |||
| 606 | ✗ | end module m_mform_eigensolver | |
| 607 |