18 USE ieee_arithmetic,
ONLY: ieee_is_finite
19#if defined(__HAS_IEEE_EXCEPTIONS)
20 USE ieee_exceptions,
ONLY: ieee_all, ieee_get_halting_mode, ieee_set_halting_mode
26#include "./base/base_uses.f90"
55 gap_tolerance, para_env, flattened, gap, metric_ratio, residuals, status)
57 INTEGER,
INTENT(IN) :: grid(3), nspin
58 REAL(
dp),
INTENT(IN) :: energy, scale, tolerance, &
59 metric_tolerance, gap_tolerance
62 REAL(
dp),
INTENT(OUT) :: gap, metric_ratio, residuals(4)
63 INTEGER,
INTENT(OUT) :: status
65 COMPLEX(dp),
ALLOCATABLE :: fk(:, :, :), hc(:, :, :), hk(:, :, :), &
66 sc(:, :, :), sk(:, :, :)
67 INTEGER :: ik, nb, ncell, ns, nscalar, nsmall, &
69 INTEGER,
ALLOCATABLE :: cell_index(:), cells(:, :), starts(:)
70 INTEGER,
POINTER :: sizes(:), ssize(:)
72 REAL(
dp) :: all_bounds(2), bounds(2), difference, &
73 errors(2), gap_threshold, local_gap, &
75 REAL(
dp),
ALLOCATABLE :: weights(:), xkp(:, :)
81 residuals = huge(1.0_dp)
82 IF (any(grid < 1) .OR. (nspin /= 1 .AND. nspin /= 2))
RETURN
83 IF (.NOT. all(ieee_is_finite([energy, scale, tolerance, metric_tolerance, gap_tolerance])))
RETURN
84 IF (scale <= 0.0_dp .OR. tolerance <= 0.0_dp .OR. tolerance >= 1.0_dp)
RETURN
85 IF (metric_tolerance <= 0.0_dp .OR. metric_tolerance >= 1.0_dp .OR. gap_tolerance < 0.0_dp)
RETURN
86 CALL dbcsr_get_info(h%real_part, nblkrows_total=nb, row_blk_size=sizes)
87 CALL dbcsr_get_info(s%real_part, nblkrows_total=ns, row_blk_size=ssize)
88 IF (nb < 1 .OR. nb /= ns)
RETURN
89 IF (any(sizes /= ssize))
RETURN
90 IF (any(sizes <= 0))
RETURN
94 IF (grid(ik) > nb/ncell)
RETURN
95 ncell = ncell*grid(ik)
97 IF (nspin > nb/ncell)
RETURN
98 IF (mod(nb, nspin*ncell) /= 0)
RETURN
101 IF (sizes(ik) /= sizes(1 +
modulo(ik - 1, ns)))
RETURN
104 IF (.NOT. valid)
RETURN
106 IF (.NOT. valid)
RETURN
107 nscalar = sum(sizes(:ns))
108 nsmall = nscalar*nspin
109 ALLOCATE (starts(nb), cell_index(nb), cells(3, ncell), xkp(3, ncell), weights(ncell))
111 starts(ik) = 1 + sum(sizes(:
modulo(ik - 1, ns))) + ((ik - 1)/(ns*ncell))*nscalar
112 cell_index(ik) = 1 +
modulo((ik - 1)/ns, ncell)
115 cells(:, ik) = [
modulo(ik - 1, grid(1)),
modulo((ik - 1)/grid(1), grid(2)), &
116 (ik - 1)/(grid(1)*grid(2))]
117 xkp(:, ik) = real(cells(:, ik),
dp)/real(grid,
dp)
119 ALLOCATE (hc(nsmall, nsmall, ncell), sc(nsmall, nsmall, ncell), &
120 hk(nsmall, nsmall, ncell), sk(nsmall, nsmall, ncell), fk(nsmall, nsmall, ncell))
121 CALL torus_blocks(h, starts, cell_index, para_env, hc)
122 CALL torus_blocks(s, starts, cell_index, para_env, sc)
125 CALL expand_blocks(hc, h, grid, starts, cell_index, para_env, reconstructed)
126 CALL matrix_difference(reconstructed, h, difference)
128 residuals(1) = difference
129 CALL expand_blocks(sc, s, grid, starts, cell_index, para_env, reconstructed)
130 CALL matrix_difference(reconstructed, s, difference)
132 residuals(1) = max(residuals(1), difference)
134 IF (.NOT. ieee_is_finite(residuals(1)) .OR. residuals(1) > tolerance)
RETURN
140 all_bounds = [huge(1.0_dp), 0.0_dp]
142 gap_threshold = gap_tolerance
145 IF (
modulo(ik - 1, para_env%num_pe) /= para_env%mepos) cycle
146 CALL flatten_block(hk(:, :, ik), sk(:, :, ik), energy, scale, tolerance, metric_tolerance, fk(:, :, ik), &
147 local_gap, bounds, threshold, errors, substatus)
148 IF (substatus /= 0)
THEN
149 status = min(status, substatus)
152 all_bounds = [min(all_bounds(1), bounds(1)), max(all_bounds(2), bounds(2))]
153 gap = min(gap, local_gap)
154 gap_threshold = max(gap_threshold, threshold)
155 residuals(2:3) = max(residuals(2:3), errors)
157 CALL para_env%min(status)
158 IF (status /= 0)
RETURN
159 CALL para_env%min(all_bounds(1))
160 CALL para_env%max(all_bounds(2))
161 CALL para_env%min(gap)
162 CALL para_env%max(gap_threshold)
163 CALL para_env%max(residuals)
164 metric_ratio = all_bounds(1)/all_bounds(2)
166 IF (metric_ratio <= metric_tolerance)
RETURN
168 IF (gap <= gap_threshold)
RETURN
170 IF (maxval(residuals) > tolerance .OR. .NOT. all(ieee_is_finite(residuals)))
RETURN
171 CALL para_env%sum(fk)
173 CALL expand_blocks(hc, h, grid, starts, cell_index, para_env, flattened)
175 IF (.NOT. valid)
THEN
190 SUBROUTINE torus_blocks(matrix, starts, cell_index, para_env, blocks)
192 INTEGER,
INTENT(IN) :: starts(:), cell_index(:)
194 COMPLEX(dp),
INTENT(OUT) :: blocks(:, :, :)
196 CALL extract(matrix%real_part, cmplx(1.0_dp, 0.0_dp,
dp), .true.)
197 CALL extract(matrix%imaginary_part, cmplx(0.0_dp, 1.0_dp,
dp), .false.)
198 CALL para_env%sum(blocks)
208 SUBROUTINE extract(component, factor, initialize)
210 COMPLEX(dp),
INTENT(IN) :: factor
211 LOGICAL,
INTENT(IN) :: initialize
213 INTEGER :: c, col, i, j, row
214 LOGICAL :: transposed
215 REAL(
dp),
POINTER :: block(:, :)
218 IF (initialize) blocks = 0.0_dp
222 cpassert(.NOT. transposed)
223 IF (cell_index(row) /= 1) cycle
227 blocks(i:i +
SIZE(block, 1) - 1, j:j +
SIZE(block, 2) - 1, c) = &
228 blocks(i:i +
SIZE(block, 1) - 1, j:j +
SIZE(block, 2) - 1, c) + factor*block
231 END SUBROUTINE extract
232 END SUBROUTINE torus_blocks
244 SUBROUTINE expand_blocks(blocks, template, grid, starts, cell_index, para_env, matrix)
245 COMPLEX(dp),
INTENT(IN) :: blocks(:, :, :)
247 INTEGER,
INTENT(IN) :: grid(3), starts(:), cell_index(:)
251 INTEGER :: row, col, i, j, c, d(3), t, u
252 INTEGER,
POINTER :: sizes(:), rows(:), cols(:), pgrid(:, :)
255 CALL dbcsr_get_info(template%real_part, distribution=distribution, row_blk_size=sizes)
257 CALL dbcsr_create(matrix%real_part, template=template%real_part)
258 CALL dbcsr_create(matrix%imaginary_part, template=template%imaginary_part)
259 DO row = 1,
SIZE(starts)
260 t = cell_index(row) - 1
262 DO col = 1,
SIZE(starts)
263 IF (pgrid(rows(row), cols(col)) /= para_env%mepos) cycle
264 u = cell_index(col) - 1
267 modulo(u/grid(1), grid(2)) -
modulo(t/grid(1), grid(2)), &
268 u/(grid(1)*grid(2)) - t/(grid(1)*grid(2))], grid)
269 c = 1 + d(1) + grid(1)*(d(2) + grid(2)*d(3))
271 REAL(blocks(i:i + sizes(row) - 1, j:j + sizes(col) - 1, c),
dp))
273 aimag(blocks(i:i + sizes(row) - 1, j:j + sizes(col) - 1, c)))
278 END SUBROUTINE expand_blocks
286 SUBROUTINE matrix_difference(trial, reference, error)
288 REAL(
dp),
INTENT(OUT) :: error
293 CALL dbcsr_add(trial%real_part, reference%real_part, 1.0_dp, -1.0_dp)
294 CALL dbcsr_add(trial%imaginary_part, reference%imaginary_part, 1.0_dp, -1.0_dp)
296 max(norm, tiny(1.0_dp))
297 END SUBROUTINE matrix_difference
314 SUBROUTINE flatten_block(h, s, energy, scale, tolerance, metric_tolerance, flat, gap, bounds, threshold, errors, status)
315 COMPLEX(dp),
INTENT(IN) :: h(:, :), s(:, :)
316 REAL(
dp),
INTENT(IN) :: energy, scale, tolerance, metric_tolerance
317 COMPLEX(dp),
INTENT(OUT) :: flat(:, :)
318 REAL(
dp),
INTENT(OUT) :: gap, bounds(2), threshold, errors(2)
319 INTEGER,
INTENT(OUT) :: status
321 COMPLEX(dp),
ALLOCATABLE :: a(:, :), b(:, :), work(:), sc(:, :), residual(:, :)
322 REAL(
dp),
ALLOCATABLE :: eigenvalues(:), rwork(:)
323 REAL(
dp) :: hnorm, snorm, herror, serror
324 INTEGER :: n, info, i
325#if defined(__HAS_IEEE_EXCEPTIONS)
326 LOGICAL :: halt(size(ieee_all))
331 IF (.NOT. all(ieee_is_finite(real(h,
dp))) .OR. .NOT. all(ieee_is_finite(aimag(h))))
RETURN
332 IF (.NOT. all(ieee_is_finite(real(s,
dp))) .OR. .NOT. all(ieee_is_finite(aimag(s))))
RETURN
333 hnorm = max(maxval(abs(h)), tiny(1.0_dp))
334 snorm = max(maxval(abs(s)), tiny(1.0_dp))
335 herror = maxval(abs(h - conjg(transpose(h))))
336 serror = maxval(abs(s - conjg(transpose(s))))
337 IF (herror > tolerance*hnorm .OR. serror > tolerance*snorm)
RETURN
338 ALLOCATE (a(n, n), b(n, n), work(max(1, 2*n)), eigenvalues(n), rwork(max(1, 3*n)))
340#if defined(__HAS_IEEE_EXCEPTIONS)
341 CALL ieee_get_halting_mode(ieee_all, halt)
342 CALL ieee_set_halting_mode(ieee_all, .false.)
344 CALL zheev(
'N',
'U', n, a, n, eigenvalues, work,
SIZE(work), rwork, info)
345#if defined(__HAS_IEEE_EXCEPTIONS)
346 CALL ieee_set_halting_mode(ieee_all, halt)
349 IF (info /= 0 .OR. .NOT. all(ieee_is_finite(eigenvalues)))
RETURN
350 bounds = [minval(eigenvalues), maxval(eigenvalues)]
352 IF (bounds(2) <= 0.0_dp .OR. bounds(1) <= metric_tolerance*bounds(2))
RETURN
353 a(:, :) = h - energy*s
355#if defined(__HAS_IEEE_EXCEPTIONS)
356 CALL ieee_set_halting_mode(ieee_all, .false.)
358 CALL zhegv(1,
'V',
'U', n, a, n, b, n, eigenvalues, work,
SIZE(work), rwork, info)
359#if defined(__HAS_IEEE_EXCEPTIONS)
360 CALL ieee_set_halting_mode(ieee_all, halt)
363 IF (info /= 0 .OR. .NOT. all(ieee_is_finite(eigenvalues)))
RETURN
364 gap = minval(abs(eigenvalues))
365 threshold = real(n,
dp)*(herror + (abs(energy) + maxval(abs(eigenvalues)))*serror)/bounds(1) + &
366 100.0_dp*epsilon(1.0_dp)*real(n,
dp)* &
367 max(maxval(abs(eigenvalues)), maxval(abs(h - energy*s))/bounds(1))
368 ALLOCATE (sc(n, n), residual(n, n))
369 sc(:, :) = matmul(s, a)
370 residual(:, :) = matmul(conjg(transpose(a)), sc)
372 residual(i, i) = residual(i, i) - 1.0_dp
374 errors(1) = sqrt(sum(abs(residual)**2))
375 residual(:, :) = matmul(h - energy*s, a) - sc*spread(eigenvalues, 1, n)
376 errors(2) = sqrt(sum(abs(residual)**2))/max(tiny(1.0_dp), &
377 sqrt(sum(abs(h - energy*s)**2))*sqrt(sum(abs(a)**2)))
378 flat = matmul(sc*spread(sign(scale, eigenvalues), 1, n), conjg(transpose(sc)))
380 END SUBROUTINE flatten_block
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
logical function, public dbcsr_iterator_blocks_left(iterator)
...
subroutine, public dbcsr_iterator_stop(iterator)
...
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
subroutine, public dbcsr_iterator_next_block(iterator, row, column, block, block_number_argument_has_been_removed, row_size, col_size, row_offset, col_offset, transposed)
...
subroutine, public dbcsr_finalize(matrix)
...
subroutine, public dbcsr_iterator_start(iterator, matrix, shared, dynamic, dynamic_byrows)
...
subroutine, public dbcsr_put_block(matrix, row, col, block, summation)
...
subroutine, public dbcsr_add(matrix_a, matrix_b, alpha_scalar, beta_scalar)
...
subroutine, public dbcsr_distribution_get(dist, row_dist, col_dist, nrows, ncols, has_threads, group, mynode, numnodes, nprows, npcols, myprow, mypcol, pgrid, subgroups_defined, prow_group, pcol_group)
...
real(dp) function, public dbcsr_frobenius_norm(matrix)
Compute the frobenius norm of a dbcsr matrix.
Defines the basic variable types.
integer, parameter, public dp
Batched lattice Fourier transforms on regular k-point grids.
subroutine, public k_grid_to_cell_fft(values_k, xkp, nkp_grid, index_to_cell, values_rs, used_fft, weights, allow_incomplete)
Transform reciprocal-grid data back to image-cell values.
Interface to the message passing library MPI.
Exact spectral flattening of a translation-invariant AO torus in primitive Bloch blocks.
subroutine, public localizer_flatten_bloch(h, s, grid, nspin, energy, scale, tolerance, metric_tolerance, gap_tolerance, para_env, flattened, gap, metric_ratio, residuals, status)
Flatten all Bloch bands, then return to the original distributed real-cell/spin AO basis.
Distributed block-sparse finite localizers, retaining the covariant AO metric.
subroutine, public localizer_dbcsr_release(matrix)
Release both real components of a complex sparse operator.
subroutine, public localizer_dbcsr_check(matrix, para_env, tolerance, valid, relative_error)
Check both components before a sparse solver discards the upper triangle.
stores all the informations relevant to an mpi environment