Octopus
isdf_serial.F90
Go to the documentation of this file.
1!! Copyright (C) 2024 - 2025. Alexander Buccheri
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, U
17
18#include "global.h"
19
22 use, intrinsic :: iso_fortran_env, only: real64
23 use batch_oct_m
25 use blas_oct_m
26 use debug_oct_m
30 use global_oct_m
31 use grid_oct_m
32 use ions_oct_m
37 use math_oct_m
38 use mesh_oct_m
41 use mpi_oct_m, only: mpi_world
49 use space_oct_m
52
53 implicit none
54 private
55
56 ! TODO(Alex) Issue #1195 Extend ISDF to spin-polarised systems
58 integer, parameter :: ik = 1
59
61 type isdf_options_t
62 integer :: n_interp
63 contains
64 procedure :: init => isdf_options_init
65 end type isdf_options_t
66
67 public :: &
71
72contains
73
75 subroutine isdf_options_init(this, namespace, st)
76 class(isdf_options_t), intent(out) :: this
77 type(namespace_t), intent(in ) :: namespace
78 type(states_elec_t), intent(in ) :: st
79
80 integer :: default_n_interp
81
82 push_sub(isdf_options_init)
83
84 default_n_interp = 10 * highest_occupied_index(st, ik)
85
86 !%Variable NCentroidPoints
87 !%Type integer
88 !%Default 10*Nocc
89 !%Section ISDF
90 !%Description
91 !% The total number of interpolation points used in ISDF density fitting.
92 !% This number should be considerably smaller than the number of grid points.
93 !% By default, Octopus sets the number of interpolation points to 10x the number
94 !% of occupied states.
95 !%End
96 call parse_variable(namespace, 'NCentroidPoints', default_n_interp, this%n_interp)
97
98 pop_sub(isdf_options_init)
99
100 end subroutine isdf_options_init
101
102
106 subroutine serial_interpolative_separable_density_fitting_vectors(namespace, mesh, st, int_indices, phi, isdf_vectors)
107 type(namespace_t), intent(in ) :: namespace
108 class(mesh_t), intent(in ) :: mesh
109 type(states_elec_t), intent(in ) :: st
110 integer(int64), contiguous, intent(in ) :: int_indices(:)
111 real(real64), allocatable, intent(out) :: phi(:, :)
112 ! of shape either:
113 ! Packed (nst, npg)
114 ! Unpacked (npg, nst)
115 real(real64), allocatable, intent(out) :: isdf_vectors(:, :)
116
117 integer :: nocc
118
120
121 message(1) = "Serial ISDF"
122 call messages_write(1)
123
124 ! Reference implementation not parallel in states or domain
125 if (st%parallel_in_states .or. mesh%parallel_in_domains) then
126 message(1) = "Serial ISDF called when running state or domain-parallel"
127 call messages_fatal(1)
128 endif
129
130 ! TODO(Alex) Issue #1195 Extend ISDF to spin-polarised systems
131 if (st%d%nspin > 1) then
132 call messages_not_implemented("ISDF Serial for SPIN_POLARIZED and SPINOR calculations", namespace)
133 endif
134
135 ! TODO(Alex) Issue #1196 Template ISDF handle both real and complex states
136 if (.not. states_are_real(st)) then
137 call messages_not_implemented("ISDF Serial handling of complex states", namespace)
138 endif
139
140 nocc = highest_occupied_index(st, ik)
141
142 ! Alternate means of constructing phi from a batch - retained for reference.
143 ! Dress in a fake code path so the compiler does not warn that the routine is unused.
144 if (.false.) then
145 call collate_batches(mesh%np, st, nocc, phi)
146 if (debug%info) call output_matrix(namespace, "phi_r_serial.txt", phi)
147 safe_deallocate_a(phi)
148 endif
149
150 ! This gives identical results to the above
151 call collate_batches_get_state(mesh, st, nocc, phi)
152 if (debug%info) call output_matrix(namespace, "phi_r_serial3.txt", phi)
153
154 select case (st%group%psib(st%group%block_start, 1)%status())
155 case (batch_device_packed)
156 message(1) = "Serial ISDF not implemented for BATCH_DEVICE_PACKED"
157 call messages_fatal(1)
158
159 case (batch_packed)
160 call isdf_construct_interpolation_vectors_packed(namespace, mesh, phi, int_indices, isdf_vectors)
161
162 case (batch_not_packed)
163 message(1) = "Serial ISDF not implemented for BATCH_NOT_PACKED"
164 call messages_fatal(1)
165 assert(all(shape(phi) == [mesh%np, st%nst]))
166
167 end select
170
172
173
177 subroutine isdf_construct_interpolation_vectors_packed(namespace, mesh, phi, indices, isdf_vectors)
178 type(namespace_t), intent(in ) :: namespace
179 class(mesh_t), intent(in ) :: mesh
180 real(real64), contiguous, intent(in ) :: phi(:, :)
181 integer(int64), contiguous, intent(in ) :: indices(:)
182 real(real64), allocatable, intent(out) :: isdf_vectors(:, :)
183
184 real(real64), allocatable :: phi_mu(:, :)
185 real(real64), allocatable :: P_mu_nu(:, :)
186 real(real64), allocatable :: zct(:, :)
187 real(real64), allocatable :: cct(:, :)
188
189 integer :: n_int, i, j, n_states
190 logical, parameter :: construct_P_mu_nu = .false.
191
193
194 assert(size(phi, 2) == mesh%np)
195
196 n_states = size(phi, 1)
197 n_int = size(indices)
198
199 safe_allocate(phi_mu(1:n_states, 1:n_int))
200 call sample_phi_at_centroids(phi, indices, phi_mu)
201 if (debug%info) call output_matrix(namespace, "phi_mu_serial.txt", phi_mu)
202
203 ! Note, this actually constructs P_r_mu, but we want to mutate the memory in the subsequent call
204 safe_allocate(zct(1:mesh%np, 1:n_int))
205 call construct_density_matrix_packed(phi, phi_mu, zct)
206 if (debug%info) call output_matrix(namespace, "p_r_mu_serial.txt", zct)
207
208 ! [ZC^T] = P_r_mu o P_r_mu
209 call construct_zct(zct)
210 if (debug%info) call output_matrix(namespace, "zct_serial.txt", zct)
211
212 ! [CC^T] = ZC^T[indices, :]
213 safe_allocate(cct(1:n_int, 1:n_int))
214 call construct_cct(indices, zct, cct)
215 if (debug%info) call output_matrix(namespace, "cct_serial.txt", cct)
216 assert(is_symmetric(cct))
217
218 ! For testing, alternately, construct [CC^T] = P_mu_nu o P_mu_nu
219 if (construct_p_mu_nu) then
220 safe_allocate(p_mu_nu(1:n_int, 1:n_int))
222 assert(is_symmetric(p_mu_nu))
223
224 safe_deallocate_a(phi_mu)
225 if (debug%info) call output_matrix(namespace, "p_mu_nu_serial.txt", p_mu_nu)
226
227 ! Mutate P_mu_nu -> cct
228 write(message(1),'(a)') "ISDF Serial: Constructing [CC^T] = P_mu_nu o P_mu_nu"
229 call messages_info(1, namespace=namespace, debug_only=.true.)
230
231 do j = 1, n_int
232 do i = 1, n_int
233 p_mu_nu(i, j) = p_mu_nu(i, j) * p_mu_nu(i, j)
234 enddo
235 enddo
236
237 if (debug%info) call output_matrix(namespace, "cct_alt_serial.txt", p_mu_nu)
238 safe_deallocate_a(p_mu_nu)
239 endif
240
241 ! [CC^T]^{-1}, mutating cct in-place
242 ! NOTE, CC^T is extremely ill-conditioned, and it is not clear why this is the case.
243 ! * Using the pseudo-inverse (SVD) circumvents this problem, without addressing the root cause
244 ! As CC^T and its inverse should be symmetric, ultimately want to:
245 ! * Only compute the inverse of the upper (or lower) triangle
246 ! * Modify the GEMM operation below to only use the upper (or lower) triangle of [CC^T]^{-1}
247 write(message(1),'(a)') "ISDF Serial: Inverting [CC^T]"
248 call messages_info(1, namespace=namespace, debug_only=.true.)
249
250 ! Invert [CC^T] and symmetrise
251 call lalg_svd_inverse(n_int, n_int, cct)
252 call symmetrize_matrix(n_int, cct)
253
254 ! Compute interpolation vectors, [ZC^T] [CC^T]^{-1}
255 safe_allocate(isdf_vectors(1:mesh%np, 1:n_int))
256
257 ! CC^T is by definition symmetric, implying [CC^T]^{-1} also is
258 call lalg_gemm(mesh%np, n_int, n_int, 1.0_real64, zct, cct, 0.0_real64, isdf_vectors)
259
260 if (debug%info) call output_matrix(namespace, "isdf_serial.txt", isdf_vectors)
261 safe_deallocate_a(zct)
262 safe_deallocate_a(cct)
263
265
267
268
272 subroutine collate_batches_get_state(mesh, st, max_state, psi)
273 class(mesh_t), intent(in ) :: mesh
274 type(states_elec_t), intent(in ) :: st
275 integer, intent(in ) :: max_state
276 real(real64), allocatable, intent(out) :: psi(:, :)
277
278 integer :: istate, ib, ist, minst, maxst, block_end
279
281
282 assert(max_state <= st%nst)
283
284 safe_allocate(psi(1:max_state, 1:mesh%np))
285 block_end = st%group%iblock(max_state)
286
287 istate = 0
288 do ib = 1, block_end
289 ! Normalisation did not affect condition number of CC^T matrix
290 !call dmesh_batch_normalize(mesh, st%group%psib(ib, ik))
291 minst = states_elec_block_min(st, ib)
292 maxst = min(states_elec_block_max(st, ib), max_state)
293 do ist = minst, maxst
294 istate = istate + 1
295 ! In case there are any states < max_state that are not occupied
296 if (abs(st%occ(ist, ik) * st%kweights(ik)) < m_min_occ) then
297 psi(istate, :) = 0.0_real64
298 else
299 call states_elec_get_state(st, mesh, st%d%dim, ist, ik, psi(istate, :))
300 endif
301 enddo
302 enddo
303
305
306 end subroutine collate_batches_get_state
307
308
310 subroutine collate_batches(np, st, max_state, psi)
311 integer, intent(in ) :: np
312 type(states_elec_t), intent(in ) :: st
313 integer, intent(in) :: max_state
314 real(real64), allocatable, intent(out) :: psi(:, :)
315
316 integer :: ip, ib, minst, maxst, block_end, ist, ist_local
317
318 push_sub(collate_batches)
319
320 select case (st%group%psib(1,1)%status())
321 case (batch_device_packed)
322 ! No GPU implementation
323 assert(.false.)
324
325 case (batch_packed)
326
327 ! Not state distributed, so expect ist to run [1: max_state], contiguously
328 safe_allocate(psi(1:max_state, 1:np))
329 block_end = st%group%iblock(max_state)
330
331 do ip = 1, np
332 do ib = 1, block_end
333 minst = states_elec_block_min(st, ib)
334 ! Truncate maxst to max_state in last block
335 maxst = min(states_elec_block_max(st, ib), max_state)
336 ! Assign states from current batch
337 do ist = minst, maxst
338 ist_local = ist - minst + 1
339 ! In case there are any states < max_state that are not occupied
340 if (abs(st%occ(ist, ik) * st%kweights(ik)) < m_min_occ) then
341 psi(ist, ip) = 0.0_real64
342 else
343 psi(ist, ip) = st%group%psib(ib, ik)%dff_pack(ist_local, ip)
344 endif
345 enddo
346 enddo
347 enddo
348
349 case (batch_not_packed)
350 assert(.false.)
351
352 end select
353
354 pop_sub(collate_batches)
355
356 end subroutine collate_batches
357
358
360 subroutine sample_phi_at_centroids(phi_r, indices, phi_mu)
361 real(real64), contiguous, intent(in ) :: phi_r(:, :)
362 integer(int64), contiguous, intent(in ) :: indices(:)
363 real(real64), contiguous, intent(out) :: phi_mu(:, :)
364
365 integer :: ic, is, nst, n_int
366 integer(int64) :: ipg
367
369
370 write(message(1),'(a)') "ISDF Serial: Sampling phi(r) at mu"
371 call messages_info(1, debug_only=.true.)
372
373 nst = size(phi_r, 1)
374 assert(size(phi_mu, 1) == nst)
375
376 n_int = size(indices)
377 assert(size(phi_mu, 2) == n_int)
378
379 do ic = 1, n_int
380 ipg = indices(ic)
381 do is = 1, nst
382 phi_mu(is, ic) = phi_r(is, ipg)
383 enddo
384 enddo
385
387
388 end subroutine sample_phi_at_centroids
389
390
401 subroutine construct_zct(zct)
402 real(real64), contiguous, intent(inout) :: zct(:, :)
403 ! Out: Contraction of Z and C^T matrices == element-wise square of quasi-density matrix
404
405 integer :: i, j
406
407 push_sub_with_profile(construct_zct)
408
409 write(message(1),'(a)') "ISDF Serial: Constructing ZC^T"
410 call messages_info(1, debug_only=.true.)
411
412 !$omp parallel do collapse(2)
413 do j = 1, size(zct, 2)
414 do i = 1, size(zct, 1)
415 zct(i, j) = zct(i, j)**2
416 end do
417 enddo
418 !$omp end parallel do
419
420 pop_sub_with_profile(construct_zct)
421
422 end subroutine construct_zct
423
424
427 subroutine construct_cct(indices, zct, cct)
428 integer(int64), contiguous, intent(in ) :: indices(:)
429 real(real64), contiguous, intent(in ) :: zct(:, :)
430
431 real(real64), contiguous, intent(out) :: cct(:, :)
432
433 integer(int64) :: ipg
434 integer :: i_mu, i_nu, n_int
435
436 push_sub_with_profile(construct_cct)
437
438 write(message(1),'(a)') "ISDF Serial: Constructing CC^T by sampling ZC^T"
439 call messages_info(1, debug_only=.true.)
440
441 n_int = size(indices)
442 assert(all(shape(cct) == [n_int, n_int]))
443 assert(size(zct, 1) > n_int)
444 assert(size(zct, 2) == n_int)
445
446 ! Mask ZC^T to obtain CC^T
447 do i_nu = 1, n_int
448 do i_mu = 1, n_int
449 ipg = indices(i_mu)
450 cct(i_mu, i_nu) = zct(ipg, i_nu)
451 enddo
452 enddo
454 pop_sub_with_profile(construct_cct)
455
456 end subroutine construct_cct
457
458
467 subroutine construct_density_matrix_packed(phi, phi_mu, P_r_mu)
468 real(real64), contiguous, intent(in ) :: phi(:, :)
469 ! of shape (m_states, np)
470 real(real64), contiguous, intent(in ) :: phi_mu(:, :)
471
472 real(real64), contiguous, intent(out) :: P_r_mu(:, :)
473
474 integer :: np
475 integer :: n_int
476 integer :: m_states
477
478 push_sub_with_profile(construct_density_matrix_packed)
479
480 write(message(1),'(a)') "ISDF Serial: Constructing P_r_mu"
481 call messages_info(1, debug_only=.true.)
482
483 m_states = size(phi, 1)
484 np = size(phi, 2)
485 n_int = size(phi_mu, 2)
486
487 assert(size(phi_mu, 1) == m_states)
488 assert(size(p_r_mu, 1) == np)
489 assert(size(p_r_mu, 2) == n_int)
490
491 ! Contract over the state index, P = phi^T @ phi_mu, with shape (np, m_states) (m_states, n_int)
492 call lalg_gemm(phi, phi_mu, p_r_mu, transa='T')
493
495
497
498
507 subroutine construct_density_matrix_all_centroids_packed(phi_mu, P_mu_nu)
508 real(real64), contiguous, intent(in ) :: phi_mu(:, :)
509 ! of shape (m_states, n_int)
510 real(real64), contiguous, intent(out) :: P_mu_nu(:, :)
511
512 integer :: n_int
513
515
516 write(message(1),'(a)') "ISDF Serial: Constructing P_mu_nu"
517 call messages_info(1, debug_only=.true.)
518
519 n_int = size(phi_mu, 2)
520 assert(size(p_mu_nu, 1) == n_int)
521 assert(size(p_mu_nu, 2) == n_int)
522
523 ! Contract over the state index
524 call lalg_gemm(phi_mu, phi_mu, p_mu_nu, transa='T')
525
527
529
530
532 subroutine quantify_error_and_visualise(namespace, st, space, mesh, ions, phi, indices, isdf_vectors, output_cubes)
533 type(namespace_t), intent(in) :: namespace
534 type(states_elec_t), intent(in) :: st
535 class(space_t), intent(in) :: space
536 class(mesh_t), intent(in) :: mesh
537 class(ions_t), pointer, intent(in) :: ions
538 real(real64), allocatable, intent(inout) :: phi(:, :)
539 integer(int64), contiguous, intent(in) :: indices(:)
540 real(real64), allocatable, intent(inout) :: isdf_vectors(:, :)
541 logical, intent(in) :: output_cubes
542
543 real(real64), allocatable :: product_basis(:, :), approx_product_basis(:, :)
544 real(real64), allocatable :: phi_mu(:, :), phi_occ(:, :)
545 real(real64), allocatable :: product_error(:)
546 integer :: n_occ, n_products, n_int, i, j, ij, is, ip, unit
547 real(real64) :: mean_error
548
550
551 write(message(1),'(a)') "ISDF Serial: Computing exact pair products"
552 call messages_info(1, debug_only=.true.)
553
554 assert(size(phi, 2) == mesh%np)
555
556 ! Limit product basis comparison to occupied states
557 n_occ = highest_occupied_index(st, ik)
558 safe_allocate(phi_occ(1:n_occ, 1:mesh%np))
559 do ip = 1, mesh%np
560 do is = 1, n_occ
561 phi_occ(is, ip) = phi(is, ip)
562 enddo
563 enddo
564 safe_deallocate_a(phi)
565
566 n_products = n_occ * n_occ
567 safe_allocate(product_basis(1:n_products, 1:mesh%np))
568 call column_wise_khatri_rao_product(phi_occ, phi_occ, product_basis)
569 ! if (debug%info) call output_matrix(namespace, "exact_product_blas.txt", product_basis)
570
571 if (output_cubes) then
572 call generate_product_state_cubes(namespace, space, mesh, ions, "exact_product_", &
573 product_basis)
574 endif
575
576 write(message(1),'(a)') "ISDF Serial Test: Computing approximate pair products"
577 call messages_info(1, namespace=namespace, debug_only=.true.)
578
579 ! Rebuild phi_mu, again only for occupied states
580 n_int = size(indices)
581 safe_allocate(phi_mu(1:n_occ, 1:n_int))
582 call sample_phi_at_centroids(phi_occ, indices, phi_mu)
583 safe_deallocate_a(phi_occ)
584
585 safe_allocate(approx_product_basis(1:n_products, 1:mesh%np))
586 call approximate_pair_products(phi_mu, isdf_vectors, approx_product_basis)
587 ! if (debug%info) call output_matrix(namespace, "approx_product_blas.txt", approx_product_basis)
588
589 safe_deallocate_a(phi_mu)
590 safe_deallocate_a(isdf_vectors)
591
592 if (output_cubes) then
593 call generate_product_state_cubes(namespace, space, mesh, ions, "approx_product_", &
594 approx_product_basis)
595 endif
596
597 ! Quantify the error
598 safe_allocate(product_error(1:n_products))
599 call error_in_product_basis(mesh, product_basis, approx_product_basis, product_error, mean_error)
600 safe_deallocate_a(product_basis)
601 safe_deallocate_a(approx_product_basis)
602
603 if (mpi_world%is_root()) then
604 open(newunit=unit, file="isdf_error_serial.txt")
605 write(unit, *) 'Mean error', mean_error
606 ij = 0
607 do i = 1, n_occ
608 do j = 1, n_occ
609 ij = ij + 1
610 write(unit, *) i, j, product_error(ij)
611 enddo
612 enddo
613 close(unit)
614 endif
615
616 safe_deallocate_a(product_error)
617
619
620 end subroutine quantify_error_and_visualise
621
632 subroutine approximate_pair_products(psi_mu, zeta, product_basis)
633 real(real64), contiguous, intent(in ) :: psi_mu(:, :)
634 real(real64), contiguous, intent(in ) :: zeta(:, :)
635 real(real64), contiguous, intent(out) :: product_basis(:, :)
636
637 real(real64), allocatable :: psi_ij_mu(:, :)
638 integer :: mn_states, n_int, np
639
641
642 mn_states = size(psi_mu, 1)**2
643 np = size(zeta, 1)
644 n_int = size(zeta, 2)
645
646 assert(size(product_basis, 1) == mn_states)
647 assert(size(product_basis, 2) == np)
648
649 safe_allocate(psi_ij_mu(1:mn_states, 1:n_int))
650 call column_wise_khatri_rao_product(psi_mu, psi_mu, psi_ij_mu)
651
652 ! Contract product_basis = [psi_ij_mu] [zeta]^T over interpolation vector index
653 call lalg_gemm(psi_ij_mu, zeta, product_basis, transb='T')
654
655 safe_deallocate_a(psi_ij_mu)
656
658
659 end subroutine approximate_pair_products
660
661
669 subroutine error_in_product_basis(mesh, product_basis, approx_product_basis, error, mean_error)
670 class(mesh_t), intent(in ) :: mesh
671 real(real64), contiguous, intent(in ) :: product_basis(:, :)
672 real(real64), contiguous, intent(in ) :: approx_product_basis(:, :)
673
674 real(real64), contiguous, intent(out) :: error(:)
675 real(real64), intent(out) :: mean_error
676
677 integer :: mn_states, np, ij, ip
678
679 push_sub(error_in_product_basis)
680
681 mn_states = size(product_basis, 1)
682 np = size(product_basis, 2)
683
684 ! product_basis shape is not as expected
685 assert(mesh%np == np)
686
687 ! Two arrays should be the same dimensions
688 assert(all(shape(product_basis) == shape(approx_product_basis)))
689
690 ! error should be allocated, and with the correct size
691 assert(size(error) == mn_states)
692
693 ! Initialise error with first point from the grid
694 do ij = 1, mn_states
695 error(ij) = (product_basis(ij, 1) - approx_product_basis(ij, 1))**2
696 enddo
697
698 do ip = 2, np
699 do ij = 1, mn_states
700 error(ij) = error(ij) + (product_basis(ij, ip) - approx_product_basis(ij, ip))**2
701 enddo
702 enddo
703
704 mean_error = 0.0_real64
705 do ij = 1, mn_states
706 error(ij) = sqrt(mesh%volume_element * error(ij))
707 mean_error = mean_error + error(ij)
708 enddo
709
710 mean_error = mean_error / real(mn_states, real64)
711
713
714 end subroutine error_in_product_basis
715
716
718 subroutine generate_product_state_cubes(namespace, space, mesh, ions, file_prefix, data, limits)
719 type(namespace_t), intent(in) :: namespace
720 class(space_t), intent(in) :: space
721 class(mesh_t), intent(in) :: mesh
722 class(ions_t), pointer, intent(in) :: ions
723 character(len=*), intent(in) :: file_prefix
724 real(real64), contiguous, intent(in) :: data(:, :)
725 integer, optional, intent(in) :: limits(2)
726
727 integer :: m_states, limit_j, limit_i, i, j, ij, ierr
728 real(real64) :: size_data
729 character(len=4) :: i_char, j_char
730 character(len=120) :: file_name
731
732 ! product basis size is currently defined as (m_states * m_states)
733 size_data = real(size(data, 1), real64)
734 m_states = int(sqrt(size_data))
735
736 if (present(limits)) then
737 limit_j = limits(1)
738 limit_i = limits(2)
739 else
740 limit_j = m_states
741 limit_i = m_states
742 endif
743
744 do i = 1, limit_i
745 do j = 1, limit_j
746 ij = j + (i - 1) * m_states
747 write(i_char, '(I4)') i
748 write(j_char, '(I4)') j
749 file_name = trim(adjustl(file_prefix)) // trim(adjustl(i_char)) // '_' // trim(adjustl(j_char))
750 call dio_function_output(option__outputformat__cube, "./cubes", trim(adjustl(file_name)), namespace, space, mesh, &
751 data(ij,:) , unit_one, ierr, pos=ions%pos, atoms=ions%atom)
752 enddo
753 enddo
754
755 end subroutine generate_product_state_cubes
756
757end module isdf_serial_oct_m
758
759!! Local Variables:
760!! mode: f90
761!! coding: utf-8
762!! End:
double sqrt(double __x) __attribute__((__nothrow__
This module implements batches of mesh functions.
Definition: batch.F90:133
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:118
This module implements the underlying real-space grid.
Definition: grid.F90:117
Serial prototype for benchmarking and validating ISDF implementation.
subroutine, public serial_interpolative_separable_density_fitting_vectors(namespace, mesh, st, int_indices, phi, isdf_vectors)
Compute a set of ISDF interpolation vectors in serial, for code validation.
subroutine, public quantify_error_and_visualise(namespace, st, space, mesh, ions, phi, indices, isdf_vectors, output_cubes)
Wrapper for quantifying the error in the expansion of the product basis.
subroutine generate_product_state_cubes(namespace, space, mesh, ions, file_prefix, data, limits)
Helper function to output a set of pair product states.
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_options_init(this, namespace, st)
Initialise isdf_inp_options_t instance.
subroutine sample_phi_at_centroids(phi_r, indices, phi_mu)
Sample KS states at centroid points.
subroutine collate_batches(np, st, max_state, psi)
Put batches into a single 2D array.
subroutine construct_density_matrix_all_centroids_packed(phi_mu, P_mu_nu)
@ brief Construct the density matrix with shape (n_int, n_int). Denoted packed, because it expects ph...
subroutine error_in_product_basis(mesh, product_basis, approx_product_basis, error, mean_error)
Quantify the error in the product basis expansion.
subroutine construct_zct(zct)
Construct the product of Z and C matrices from the element-wise product of the quasi-density matrix.
subroutine isdf_construct_interpolation_vectors_packed(namespace, mesh, phi, indices, isdf_vectors)
Compute a set of ISDF interpolation vectors, where intermediate quantities such as phi are constructe...
subroutine construct_cct(indices, zct, cct)
Construct the product from by masking the first dimension of .
integer, parameter ik
Hard-coded for Gamma-point, spin-unpolarised calculations.
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.
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
This module defines functions over batches of mesh functions.
Definition: mesh_batch.F90:116
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:270
integer, parameter, public smear_semiconductor
Definition: smear.F90:171
pure logical function, public states_are_real(st)
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_angstrom
For XYZ files.
type(unit_t), public unit_one
some special units required for particular quantities
Class describing the electron system.
Definition: electrons.F90:218
int true(void)