22 use,
intrinsic :: iso_fortran_env, only: real64, int64
65 integer,
parameter :: ik = 1
73 type(isdf_options_t),
intent(in ) :: isdf
74 type(namespace_t),
intent(in ) :: namespace
75 class(mesh_t),
intent(in ) :: mesh
76 type(states_elec_t),
intent(in ) :: st
77 integer(int64),
contiguous,
intent(in ) :: indices(:)
79 real(real64),
allocatable,
intent(out) :: phi_mu(:, :)
81 real(real64),
allocatable,
intent(out) :: P_r_mu(:, :)
83 real(real64),
allocatable,
intent(out) :: isdf_vectors(:, :)
85 real(real64),
allocatable :: phi(:, :), cct(:, :)
86 integer :: n_states, n_int, rank
87 logical :: data_is_packed
93 if (st%parallel_in_states .or. mesh%parallel_in_domains)
then
94 message(1) =
"Serial ISDF called when running state or domain-parallel"
99 if (st%d%nspin > 1)
then
109 data_is_packed = st%group%psib(st%group%block_start, 1)%status() ==
batch_packed
111 if (.not. data_is_packed)
then
112 message(1) =
"Serial ISDF only implemented for BATCH_PACKED"
116 n_states = isdf%n_ks_states
117 n_int =
size(indices)
122 safe_allocate(phi_mu(1:n_states, 1:n_int))
126 safe_allocate(p_r_mu(1:mesh%np, 1:n_int))
135 safe_allocate(cct(1:n_int, 1:n_int))
145 if (isdf%check_n_interp)
then
147 write(
message(1),
'(a, I4)')
"ISDF Serial: Rank of CC^T is ", rank
148 if (rank < n_int)
then
149 write(
message(2),
'(a)')
" - This rank is the optimal ISDFNpoints to run the calculation with"
151 write(
message(2),
'(a)')
" - This suggests that ISDFNpoints is either optimal, or could be larger"
166 write(
message(1),
'(a)')
"ISDF Serial: Inverting [CC^T]"
174 safe_allocate(isdf_vectors(1:mesh%np, 1:n_int))
176 call lalg_gemm(mesh%np, n_int, n_int, 1.0_real64, p_r_mu, cct, 0.0_real64, isdf_vectors)
178 safe_deallocate_a(cct)
182 safe_deallocate_a(phi)
194 class(
mesh_t),
intent(in ) :: mesh
196 integer,
intent(in ) :: max_state
197 real(real64),
allocatable,
intent(out) :: psi(:, :)
199 integer :: istate, ib, ist, minst, maxst, block_end
203 assert(max_state > 0 .and. max_state <= st%nst)
205 safe_allocate(psi(1:max_state, 1:mesh%np))
206 block_end = st%group%iblock(max_state)
214 do ist = minst, maxst
227 real(real64),
contiguous,
intent(in ) :: phi_r(:, :)
228 integer(int64),
contiguous,
intent(in ) :: indices(:)
229 real(real64),
contiguous,
intent(out) :: phi_mu(:, :)
231 integer :: ic, is, nst, n_int
232 integer(int64) :: ipg
236 write(
message(1),
'(a)')
"ISDF Serial: Sampling phi(r) at mu"
240 assert(
size(phi_mu, 1) == nst)
242 n_int =
size(indices)
243 assert(
size(phi_mu, 2) == n_int)
248 phi_mu(is, ic) = phi_r(is, ipg)
268 real(real64),
contiguous,
intent(inout) :: zct(:, :)
275 write(
message(1),
'(a)')
"ISDF Serial: Constructing ZC^T"
279 do j = 1,
size(zct, 2)
280 do i = 1,
size(zct, 1)
281 zct(i, j) = zct(i, j)**2
294 integer(int64),
contiguous,
intent(in ) :: indices(:)
295 real(real64),
contiguous,
intent(in ) :: zct(:, :)
297 real(real64),
contiguous,
intent(out) :: cct(:, :)
299 integer(int64) :: ipg
300 integer :: i_mu, i_nu, n_int
304 write(
message(1),
'(a)')
"ISDF Serial: Constructing CC^T by sampling ZC^T"
307 n_int =
size(indices)
308 assert(all(shape(cct) == [n_int, n_int]))
309 assert(
size(zct, 1) > n_int)
310 assert(
size(zct, 2) == n_int)
316 cct(i_mu, i_nu) = zct(ipg, i_nu)
334 real(real64),
contiguous,
intent(in ) :: phi(:, :)
336 real(real64),
contiguous,
intent(in ) :: phi_mu(:, :)
338 real(real64),
contiguous,
intent(out) :: P_r_mu(:, :)
346 write(
message(1),
'(a)')
"ISDF Serial: Constructing P_r_mu"
349 m_states =
size(phi, 1)
351 n_int =
size(phi_mu, 2)
353 assert(
size(phi_mu, 1) == m_states)
354 assert(
size(p_r_mu, 1) == np)
355 assert(
size(p_r_mu, 2) == n_int)
358 call lalg_gemm(phi, phi_mu, p_r_mu, transa=
'T')
367 real(real64),
contiguous,
intent(in ) :: phi(:, :)
369 real(real64),
contiguous,
intent(in ) :: phi_mu(:, :)
371 real(real64),
contiguous,
intent(out) :: P_r_mu(:, :)
373 integer :: np, n_int, m_states, imu, ist
374 real(real64),
allocatable :: focc_phi_mu(:, :)
376 push_sub_with_profile(construct_p_with_occ_packed)
378 write(
message(1),
'(a)')
"ISDF Serial: Constructing P_r_mu with occupations"
381 m_states =
size(phi_mu, 1)
383 n_int =
size(phi_mu, 2)
385 assert(
size(phi, 1) == m_states)
386 assert(
size(p_r_mu, 1) == np)
387 assert(
size(p_r_mu, 2) == n_int)
390 safe_allocate(focc_phi_mu(1:m_states, 1:n_int))
393 focc_phi_mu(ist, imu) = st%kweights(ik) * st%occ(ist, ik) * phi_mu(ist, imu)
398 call lalg_gemm(phi, focc_phi_mu, p_r_mu, transa=
'T')
399 safe_deallocate_a(focc_phi_mu)
401 pop_sub_with_profile(construct_p_with_occ_packed)
411 class(
space_t),
intent(in) :: space
412 class(
mesh_t),
intent(in) :: mesh
413 class(
ions_t),
pointer,
intent(in) :: ions
414 integer(int64),
contiguous,
intent(in) :: indices(:)
415 real(real64),
allocatable,
intent(inout) :: isdf_vectors(:, :)
416 logical,
intent(in) :: output_cubes
418 real(real64),
allocatable :: product_basis(:, :), approx_product_basis(:, :)
419 real(real64),
allocatable :: phi(:, :), phi_mu(:, :)
420 real(real64),
allocatable :: product_error(:)
421 integer :: n_occ, n_products, n_int, i, j, ij, unit
422 real(real64) :: mean_error
426 write(
message(1),
'(a)')
"ISDF Serial: Computing exact pair products"
430 n_occ = isdf%n_ks_states
432 assert(
size(phi, 2) == mesh%np)
434 n_products = n_occ * n_occ
435 safe_allocate(product_basis(1:n_products, 1:mesh%np))
438 if (output_cubes)
then
443 write(
message(1),
'(a)')
"ISDF Serial Test: Computing approximate pair products"
447 n_int =
size(indices)
448 safe_allocate(phi_mu(1:n_occ, 1:n_int))
450 safe_deallocate_a(phi)
452 safe_allocate(approx_product_basis(1:n_products, 1:mesh%np))
456 safe_deallocate_a(phi_mu)
457 safe_deallocate_a(isdf_vectors)
459 if (output_cubes)
then
461 approx_product_basis)
465 safe_allocate(product_error(1:n_products))
467 safe_deallocate_a(product_basis)
468 safe_deallocate_a(approx_product_basis)
470 if (st%system_grp%is_root())
then
471 open(newunit=unit, file=
"isdf_error_serial.txt")
472 write(unit, *)
'Mean error', mean_error
477 write(unit, *) i, j, product_error(ij)
483 safe_deallocate_a(product_error)
501 real(real64),
contiguous,
intent(in ) :: psi_mu(:, :)
502 real(real64),
contiguous,
intent(in ) :: zeta(:, :)
503 real(real64),
contiguous,
intent(out) :: product_basis(:, :)
505 real(real64),
allocatable :: psi_ij_mu(:, :)
506 integer :: mn_states, n_int, np
510 mn_states =
size(psi_mu, 1)**2
512 n_int =
size(zeta, 2)
514 assert(
size(product_basis, 1) == mn_states)
515 assert(
size(product_basis, 2) == np)
517 safe_allocate(psi_ij_mu(1:mn_states, 1:n_int))
521 call lalg_gemm(psi_ij_mu, zeta, product_basis, transb=
'T')
523 safe_deallocate_a(psi_ij_mu)
538 class(
mesh_t),
intent(in ) :: mesh
539 real(real64),
contiguous,
intent(in ) :: product_basis(:, :)
540 real(real64),
contiguous,
intent(in ) :: approx_product_basis(:, :)
542 real(real64),
contiguous,
intent(out) :: error(:)
543 real(real64),
intent(out) :: mean_error
545 integer :: mn_states, np, ij, ip
549 mn_states =
size(product_basis, 1)
550 np =
size(product_basis, 2)
553 assert(mesh%np == np)
556 assert(all(shape(product_basis) == shape(approx_product_basis)))
559 assert(
size(error) == mn_states)
563 error(ij) = (product_basis(ij, 1) - approx_product_basis(ij, 1))**2
568 error(ij) = error(ij) + (product_basis(ij, ip) - approx_product_basis(ij, ip))**2
572 mean_error = 0.0_real64
574 error(ij) =
sqrt(mesh%volume_element * error(ij))
575 mean_error = mean_error + error(ij)
578 mean_error = mean_error / real(mn_states, real64)
588 class(
space_t),
intent(in) :: space
589 class(
mesh_t),
intent(in) :: mesh
590 class(
ions_t),
pointer,
intent(in) :: ions
591 character(len=*),
intent(in) :: file_prefix
592 real(real64),
contiguous,
intent(in) :: data(:, :)
593 integer,
optional,
intent(in) :: limits(2)
595 integer :: m_states, limit_j, limit_i, i, j, ij, ierr
596 real(real64) :: size_data
597 character(len=4) :: i_char, j_char
598 character(len=120) :: file_name
601 size_data = real(
size(
data, 1), real64)
602 m_states = int(
sqrt(size_data))
604 if (
present(limits))
then
614 ij = j + (i - 1) * m_states
615 write(i_char,
'(I4)') i
616 write(j_char,
'(I4)') j
617 file_name = trim(adjustl(file_prefix)) // trim(adjustl(i_char)) //
'_' // trim(adjustl(j_char))
618 call dio_function_output(option__outputformat__cube,
"./cubes", trim(adjustl(file_name)), namespace, space, mesh, &
619 data(ij,:) ,
unit_one, ierr, pos=ions%pos, atoms=ions%atom)
644 class(
space_t),
intent(in ) :: space
646 class(
mesh_t),
intent(in ) :: mesh
653 real(real64),
allocatable :: psi_mu(:, :), P_r_mu(:, :), W_ace(:, :), isdf_vectors(:, :)
654 integer(int64),
allocatable :: indices(:)
659 assert(kpoints%gamma_only())
660 assert(.not. space%is_periodic())
661 assert(st%d%nspin == 1)
663 indices = exxop%isdf%centroids%global_mesh_indices()
666 indices, psi_mu, p_r_mu, isdf_vectors)
668 safe_allocate(w_ace(1:mesh%np, exxop%isdf%n_ks_states))
670 safe_deallocate_a(psi_mu)
671 safe_deallocate_a(p_r_mu)
672 safe_deallocate_a(isdf_vectors)
675 safe_deallocate_a(w_ace)
691 real(real64),
intent(in ),
contiguous :: P_r_mu(:, :)
692 real(real64),
intent(in ),
contiguous :: isdf_vectors(:, :)
693 real(real64),
intent(in ),
contiguous :: psi_mu(:, :)
694 type(
poisson_t),
intent(in ) :: poisson_solver
698 real(real64),
intent(out),
contiguous :: W_ace(:, :)
700 integer :: ip, i_mu, ist, np, n_int, nst
701 real(real64) :: psi_ist_mu
702 real(real64),
allocatable :: V_r_nu(:, :)
703 logical :: use_external_kernel
704 real(real64) :: exx_weight
705 real(real64) :: weight
710 nst =
size(psi_mu, 1)
712 n_int =
size(p_r_mu, 2)
714 assert(all(shape(p_r_mu) == shape(isdf_vectors)))
715 assert(
size(psi_mu, 2) == n_int)
716 assert(
size(w_ace, 1) == np)
718 assert(
size(w_ace, 2) == nst)
720 use_external_kernel = (st%nik > st%d%spin_channels .or. cam%omega >
m_epsilon)
721 if (use_external_kernel)
then
722 message(1) =
"External kernel not supported in ISDF"
725 exx_weight = cam%alpha
726 weight = exx_weight / st%smear%el_per_state
728 safe_allocate(v_r_nu(1:np, 1:n_int))
731 call dpoisson_solve(poisson_solver, namespace, v_r_nu(:, i_mu), isdf_vectors(:, i_mu), all_nodes=.false.)
735 write(
message(1),
'(a)')
"ISDF: Writing V from isdf_ace_w_unpacked"
741 psi_ist_mu = weight * psi_mu(ist, i_mu)
743 w_ace(ip, ist) = - (p_r_mu(ip, i_mu) * v_r_nu(ip, i_mu) * psi_ist_mu)
750 psi_ist_mu = weight * psi_mu(ist, i_mu)
752 w_ace(ip, ist) = w_ace(ip, ist) - (p_r_mu(ip, i_mu) * v_r_nu(ip, i_mu) * psi_ist_mu)
757 safe_deallocate_a(v_r_nu)
770 real(real64),
intent(in ),
contiguous :: w_ace(:, :)
774 integer :: ist, ib, ist_b, np, max_state, minst, maxst, block_end, block_size
778 assert(
size(w_ace, 2) == isdf%n_ks_states)
779 assert(st%d%dim == 1)
787 max_state = min(isdf%n_ks_states, st%st_end)
788 block_end = min(st%group%block_end, st%group%iblock(max_state))
790 do ib = st%group%block_start, block_end
793 block_size = maxst - minst + 1
795 do ist_b = 1, block_size
797 ist = minst - 1 + ist_b
798 call batch_set_state(vx_on_st%group%psib(ib, 1), ist_b, np, w_ace(:, ist))
There are several ways how to call batch_set_state and batch_get_state:
Matrix-matrix multiplication plus matrix.
double sqrt(double __x) __attribute__((__nothrow__
This module implements batches of mesh functions.
integer, parameter, public batch_packed
functions are stored in CPU memory, in transposed (packed) order
This module implements common operations on batches of mesh functions.
This module contains interfaces for BLAS routines You should not use these routines directly....
type(debug_t), save, public debug
subroutine, public column_wise_khatri_rao_product(y, x, z)
Column-wise Kronecker product.
real(real64), parameter, public m_epsilon
This module implements the underlying real-space grid.
subroutine, public dio_function_output(how, dir, fname, namespace, space, mesh, ff, unit, ierr, pos, atoms, grp, root)
Top-level IO routine for functions defined on the mesh.
Serial prototype for benchmarking and validating ISDF implementation.
subroutine generate_product_state_cubes(namespace, space, mesh, ions, file_prefix, data, limits)
Helper function to output a set of pair product states.
subroutine construct_density_matrix_with_occ_packed(st, phi, phi_mu, P_r_mu)
subroutine collate_batches_get_state(mesh, st, max_state, psi)
Loop over states per block, which makes applying the maximum state limit much simpler Use this to com...
subroutine isdf_serial_ace_w_unpacked(namespace, P_r_mu, isdf_vectors, psi_mu, poisson_solver, cam, st, W_ace)
Compute the action of the exchange potential on KS states for adaptively-compressed exchange.
subroutine sample_phi_at_centroids(phi_r, indices, phi_mu)
Sample KS states at centroid points.
subroutine, public isdf_serial_interpolation_vectors(isdf, namespace, mesh, st, indices, phi_mu, P_r_mu, isdf_vectors)
Construct interpolative separable density fitting (ISDF) vectors and other intermediate quantities re...
subroutine error_in_product_basis(mesh, product_basis, approx_product_basis, error, mean_error)
Quantify the error in the product basis expansion.
subroutine, public isdf_serial_ace_compute_potentials(exxop, namespace, space, mesh, st, Vx_on_st, kpoints)
ISDF wrapper computing interpolation points and vectors, which are used to build the potential used ...
subroutine construct_zct(zct)
Construct the product of Z and C matrices from the element-wise product of the quasi-density matrix.
subroutine construct_cct(indices, zct, cct)
Construct the product from by masking the first dimension of .
subroutine construct_density_matrix_packed(phi, phi_mu, P_r_mu)
@ brief Construct the density matrix with shape (np, n_int). Denoted packed, because it expects phi i...
subroutine approximate_pair_products(psi_mu, zeta, product_basis)
Construct a set of approximate pair products using the ISDF interpolation vectors.
subroutine, public quantify_error_and_visualise(isdf, namespace, st, space, mesh, ions, indices, isdf_vectors, output_cubes)
Wrapper for quantifying the error in the expansion of the product basis.
subroutine isdf_serial_ace_batch_w(isdf, st, W_ace, Vx_on_st)
Put the bare array representation of W into a batch.
subroutine, public output_matrix(namespace, fname, matrix)
Helper routine to output a 2D matrix.
This module is intended to contain "only mathematical" functions and procedures.
logical function, public is_symmetric(a, tol)
Check if a 2D array is symmetric.
This module defines functions over batches of mesh functions.
This module defines the meshes, which are used in Octopus.
subroutine, public messages_not_implemented(feature, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Calculates the Poisson equation. Given the density returns the corresponding potential.
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
pure logical function, public states_are_real(st)
integer pure function, public states_elec_block_max(st, ib)
return index of last state in block ib
subroutine, public states_elec_copy(stout, stin, exclude_wfns, exclude_eigenval, special, dest_type, copy_data)
make a (selective) copy of a states_elec_t object
integer pure function, public states_elec_block_min(st, ib)
return index of first state in block ib
subroutine, public states_elec_set_zero(st)
Explicitly set all wave functions in the states to zero.
This module provides routines for communicating states when using states parallelization.
This module defines the unit system, used for input and output.
type(unit_t), public unit_one
some special units required for particular quantities
Describes mesh distribution to nodes.
The states_elec_t class contains all electronic wave functions.
Coulomb-attenuating method parameters, used in the partitioning of the Coulomb potential into a short...