12 USE omp_lib,
ONLY: omp_get_max_threads,&
67#include "../base/base_uses.f90"
73 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'skala_gpw_functional'
74 INTEGER,
PARAMETER,
PRIVATE :: atom_chunk_auto_max_rows = 400000, &
75 atom_chunk_auto_min_rows = 100000, &
76 atom_chunk_auto_row_quantum = 100000, &
77 ncollapsed_grad_per_point = 5, ngrad_per_point = 10
83 TYPE skala_gapw_atom_cuda_tensor_cache_type
85 density_t, grad_t, grid_coords_t, &
87 END TYPE skala_gapw_atom_cuda_tensor_cache_type
99 TYPE(skala_gapw_atom_cuda_tensor_cache_type),
SAVE,
TARGET :: cached_atom_cuda_tensors
100 CHARACTER(len=default_path_length),
SAVE :: cached_model_path =
""
101 LOGICAL,
SAVE :: cached_model_loaded = .false.
102 LOGICAL,
SAVE :: cached_model_fp64 = .false.
103 INTEGER,
SAVE :: cached_model_cuda_device = -3
104 INTEGER,
SAVE :: logged_cuda_device = -3, &
105 logged_cuda_device_count = -1, &
106 logged_cuda_nproc = -1, &
107 logged_cuda_request = -3
118 LOGICAL :: uses_native_grid
122 uses_native_grid = .false.
124 IF (
ASSOCIATED(gauxc_section))
THEN
137 INTEGER :: representation
145 cpassert(
ASSOCIATED(gauxc_section))
147 i_val=representation)
149 SELECT CASE (representation)
154 CALL cp_abort(__location__,
"Unknown pseudopotential GAPW representation.")
166 LOGICAL :: uses_native_evaluator
181 LOGICAL :: use_composite_reference
183 LOGICAL :: native_grid
186 use_composite_reference = .false.
187 native_grid = .false.
189 IF (
ASSOCIATED(gauxc_section))
THEN
192 l_val=use_composite_reference)
194 use_composite_reference = native_grid .AND. use_composite_reference
205 LOGICAL :: use_atom_composite
207 LOGICAL :: native_grid
210 use_atom_composite = .false.
211 native_grid = .false.
213 IF (
ASSOCIATED(gauxc_section))
THEN
216 "NATIVE_GRID_GAPW_ATOM_COMPOSITE_REFERENCE", &
217 l_val=use_atom_composite)
219 use_atom_composite = native_grid .AND. use_atom_composite
230 LOGICAL :: use_atom_composite
232 INTEGER :: composite_grid
235 use_atom_composite = .false.
238 IF (
ASSOCIATED(gauxc_section))
THEN
240 i_val=composite_grid)
242 SELECT CASE (composite_grid)
246 use_atom_composite = .true.
248 CALL cp_abort(__location__,
"Unknown native-grid layout.")
260 LOGICAL :: use_direct_ao
264 use_direct_ao = .false.
266 IF (
ASSOCIATED(gauxc_section))
THEN
281 LOGICAL :: uses_gauxc_model
283 CHARACTER(len=default_path_length) :: model_key, model_name, xc_key, xc_name
286 uses_gauxc_model = .false.
288 IF (
ASSOCIATED(gauxc_section))
THEN
291 model_key = adjustl(model_name)
292 xc_key = adjustl(xc_name)
295 uses_gauxc_model = (trim(model_key) /=
"" .AND. trim(model_key) /=
"NONE" .AND. &
296 trim(model_key) /= trim(xc_key))
314 IF (
ASSOCIATED(gauxc_section))
THEN
319 SELECT CASE (partition)
326 CALL cp_abort(__location__, &
327 "Unknown GAUXC%NATIVE_GRID_GAPW_DENSITY_PARTITION value.")
339 CHARACTER(len=default_path_length) :: model_key, model_name
340 INTEGER :: ifun, nfun
341 LOGICAL :: native_grid
344 NULLIFY (gauxc_section)
345 IF (.NOT.
ASSOCIATED(xc_section))
THEN
346 cpabort(
"Native SKALA GPW requires an XC section")
350 IF (.NOT.
ASSOCIATED(functionals))
THEN
351 cpabort(
"Native SKALA GPW requires an XC_FUNCTIONAL section")
359 IF (.NOT.
ASSOCIATED(xc_fun))
EXIT
361 IF (xc_fun%section%name ==
"GAUXC") gauxc_section => xc_fun
364 IF (.NOT.
ASSOCIATED(gauxc_section))
THEN
365 cpabort(
"Native SKALA GPW requires an XC_FUNCTIONAL%GAUXC section")
368 cpabort(
"Native SKALA GPW requires GAUXC to be the only XC functional")
372 IF (.NOT. native_grid .AND. &
376 model_key = adjustl(model_name)
378 IF (trim(model_key) ==
"NONE" .OR. trim(model_key) ==
"")
THEN
379 cpabort(
"Native SKALA GPW requires GAUXC%MODEL SKALA or a TorchScript model path")
402 SUBROUTINE skala_gpw_eval(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, &
403 weights, pw_pool, particle_set, cell, compute_virial, virial_xc, &
404 just_energy, atom_force)
406 REAL(kind=
dp),
INTENT(OUT) :: exc
415 LOGICAL,
INTENT(IN) :: compute_virial
416 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(OUT) :: virial_xc
417 LOGICAL,
INTENT(IN),
OPTIONAL :: just_energy
418 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT), &
419 OPTIONAL :: atom_force
421 CHARACTER(len=default_path_length) :: model_path
422 INTEGER :: i, ipt, ispin, iw, j, k, native_grid_atom_chunk_max_rows, &
423 native_grid_atom_partition, native_grid_atom_subchunks, native_grid_cuda_device, nspins, &
424 omp_max_threads_restore, phase_handle, selected_cuda_device, xc_deriv_method_id, &
426 INTEGER,
DIMENSION(2, 3) :: bo
427 LOGICAL :: has_atom_chunk_work, have_atom_coord_grad, lsd, my_just_energy, &
428 native_grid_atom_chunk_routing, native_grid_atom_chunks, native_grid_diagnostics, &
429 native_grid_use_cuda, needs_atom_force, use_atom_subchunks
430 REAL(kind=
dp) :: density_contraction, tau_contraction
431 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: density_grad, kin_grad
432 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: grad_grad
433 REAL(kind=
dp),
DIMENSION(3, 3) :: virial_before
437 atomic_grid_weight_grad_t, exc_tensor, &
438 grid_coord_grad_t, grid_weight_grad_t
444 my_just_energy = .false.
445 IF (
PRESENT(just_energy)) my_just_energy = just_energy
446 needs_atom_force =
PRESENT(atom_force)
447 IF (needs_atom_force) atom_force = 0.0_dp
448 have_atom_coord_grad = .false.
449 omp_max_threads_restore = omp_get_max_threads()
451 IF (compute_virial .AND. my_just_energy)
THEN
452 CALL cp_abort(__location__, &
453 "Native SKALA GPW stress/virial requires feature gradients.")
455 IF (.NOT.
ASSOCIATED(rho_g))
THEN
456 CALL cp_abort(__location__, &
457 "Native SKALA GPW requires the reciprocal-space density to form density gradients.")
459 IF (.NOT.
ASSOCIATED(tau))
THEN
460 CALL cp_abort(__location__, &
461 "Native SKALA GPW requires the kinetic-energy density.")
466 CALL get_skala_model_path(xc_section, model_path)
470 i_val=native_grid_cuda_device)
472 l_val=native_grid_atom_chunks)
474 l_val=native_grid_atom_chunk_routing)
476 i_val=native_grid_atom_chunk_max_rows)
478 i_val=native_grid_atom_partition)
479 SELECT CASE (native_grid_atom_partition)
485 CALL cp_abort(__location__, &
486 "Unknown GAUXC%NATIVE_GRID_ATOM_PARTITION value.")
488 native_grid_atom_chunk_routing = native_grid_atom_chunk_routing .OR. native_grid_atom_chunks
489 native_grid_atom_chunks = native_grid_atom_chunks .OR. native_grid_atom_chunk_routing
490 IF (native_grid_atom_chunk_max_rows < -1)
THEN
491 CALL cp_abort(__location__, &
492 "GAUXC%NATIVE_GRID_ATOM_CHUNK_MAX_ROWS must be -1, zero, or positive.")
494 IF (needs_atom_force .OR. compute_virial)
THEN
498 native_grid_atom_chunk_routing = .false.
499 native_grid_atom_chunks = .false.
503 selected_cuda_device = configure_native_grid_cuda( &
504 native_grid_use_cuda, native_grid_cuda_device, rho_r(1)%pw_grid%para%group)
505 CALL ensure_model_loaded(model_path, selected_cuda_device, xc_section)
508 needs%rho_spin = .true.
509 needs%drho_spin = .true.
510 needs%tau_spin = .true.
521 rho_r(1)%pw_grid%bounds_local, &
526 xc_deriv_method_id, xc_rho_smooth_id, pw_pool)
529 requires_grad=(.NOT. my_just_energy), weights=weights, &
530 requires_coordinate_grad=(needs_atom_force .OR. compute_virial), &
531 requires_stress_grad=compute_virial, &
532 use_atom_chunks=native_grid_atom_chunks, &
533 route_atom_chunks=native_grid_atom_chunk_routing, &
534 atom_partition=native_grid_atom_partition)
535 CALL section_vals_val_get(gauxc_section,
"NATIVE_GRID_DIAGNOSTICS", l_val=native_grid_diagnostics)
536 IF (native_grid_diagnostics)
THEN
537 CALL print_native_grid_diagnostics(features, rho_r(1)%pw_grid%para%group%mepos == 0)
540 IF (features%uses_atom_chunks .AND. native_grid_atom_chunk_max_rows == -1)
THEN
541 native_grid_atom_chunk_max_rows = auto_atom_chunk_max_rows(features, &
542 rho_r(1)%pw_grid%para%group)
544 IF (native_grid_diagnostics .AND. features%uses_atom_chunks .AND. &
545 rho_r(1)%pw_grid%para%group%mepos == 0)
THEN
548 WRITE (unit=iw, fmt=
"(T2,A,1X,I0)") &
549 "SKALA_GPW| Native grid atom chunk max rows", native_grid_atom_chunk_max_rows
552 native_grid_atom_subchunks = 1
553 IF (features%uses_atom_chunks .AND. native_grid_atom_chunk_max_rows > 0)
THEN
555 CALL rho_r(1)%pw_grid%para%group%max(native_grid_atom_subchunks)
557 use_atom_subchunks = features%uses_atom_chunks .AND. native_grid_atom_subchunks > 1
558 has_atom_chunk_work = .NOT. features%uses_atom_chunks .OR. features%chunk_feature_count > 0
560 IF (use_atom_subchunks)
THEN
561 CALL evaluate_atom_subchunks(features, rho_r(1)%pw_grid%para%group, &
562 native_grid_atom_chunk_max_rows, &
563 compute_grads=(.NOT. my_just_energy), exc=exc, &
564 density_grad=density_grad, grad_grad=grad_grad, &
565 kin_grad=kin_grad, collapse_spin_grads=(nspins == 1))
566 ELSE IF (has_atom_chunk_work)
THEN
568 features%grid_weights_t, exc_tensor, exc)
570 IF (features%uses_atom_chunks)
CALL rho_r(1)%pw_grid%para%group%sum(exc)
572 IF (.NOT. my_just_energy)
THEN
573 IF (.NOT. use_atom_subchunks)
THEN
574 IF (has_atom_chunk_work)
THEN
575 CALL timeset(
"skala_gpw_backward", phase_handle)
577 CALL timestop(phase_handle)
579 IF (compute_virial)
THEN
580 IF (native_grid_diagnostics) virial_before = virial_xc
581 CALL build_weight_virial(virial_xc, features, exc, grid_weight_grad_t, &
582 atomic_grid_weight_grad_t, &
583 rho_r(1)%pw_grid%para%group%mepos == 0, &
584 native_grid_diagnostics)
585 IF (native_grid_diagnostics)
THEN
586 CALL print_virial_delta(
"weight-residual", virial_xc - virial_before, &
587 rho_r(1)%pw_grid%para%group%mepos == 0)
592 CALL timeset(
"skala_gpw_grad_fetch", phase_handle)
593 IF (features%uses_atom_chunks)
THEN
594 CALL fetch_and_gather_atom_chunk_grads(features, rho_r(1)%pw_grid%para%group, &
595 density_grad, grad_grad, kin_grad)
597 CALL fetch_local_feature_grads(features, density_grad, grad_grad, kin_grad)
599 CALL timestop(phase_handle)
601 IF (needs_atom_force)
THEN
602 CALL add_explicit_coordinate_force(atom_force, features, atom_coord_grad_t, &
603 rho_r(1)%pw_grid%para%group%mepos == 0)
605 CALL add_smooth_partition_force(atom_force, features, particle_set, cell, rho_r, &
606 grid_weight_grad_t, atomic_grid_weight_grad_t)
608 have_atom_coord_grad = .true.
611 CALL timeset(
"skala_gpw_vxc_unpack", phase_handle)
612 IF (native_grid_diagnostics)
THEN
613 bo = rho_r(1)%pw_grid%bounds_local
614 density_contraction = 0.0_dp
615 tau_contraction = 0.0_dp
617 DO k = bo(1, 3), bo(2, 3)
618 DO j = bo(1, 2), bo(2, 2)
619 DO i = bo(1, 1), bo(2, 1)
621 IF (nspins == 1)
THEN
622 density_contraction = density_contraction + rho_r(1)%array(i, j, k)* &
623 0.5_dp*(density_grad(ipt, 1) + density_grad(ipt, 2))
624 tau_contraction = tau_contraction + tau(1)%array(i, j, k)* &
625 0.5_dp*(kin_grad(ipt, 1) + kin_grad(ipt, 2))
628 density_contraction = density_contraction + &
629 rho_r(ispin)%array(i, j, k)*density_grad(ipt, ispin)
630 tau_contraction = tau_contraction + &
631 tau(ispin)%array(i, j, k)*kin_grad(ipt, ispin)
637 CALL rho_r(1)%pw_grid%para%group%sum(density_contraction)
638 CALL rho_r(1)%pw_grid%para%group%sum(tau_contraction)
639 IF (rho_r(1)%pw_grid%para%group%mepos == 0)
THEN
642 WRITE (iw,
"(T2,A,1X,ES20.10)") &
643 "SKALA_GPW| XC density-gradient contraction", density_contraction
644 WRITE (iw,
"(T2,A,1X,ES20.10)") &
645 "SKALA_GPW| XC kinetic-gradient contraction", tau_contraction
649 IF (compute_virial)
THEN
650 IF (native_grid_diagnostics) virial_before = virial_xc
651 CALL build_virial_from_feature_grads(virial_xc, rho_set, rho_r, grad_grad)
652 IF (native_grid_diagnostics)
THEN
653 CALL print_virial_delta(
"feature-gradient", virial_xc - virial_before, &
654 rho_r(1)%pw_grid%para%group%mepos == 0)
655 virial_before = virial_xc
657 IF (.NOT. have_atom_coord_grad)
THEN
659 have_atom_coord_grad = .true.
661 CALL build_static_coordinate_virial(virial_xc, features, atom_coord_grad_t, &
663 rho_r(1)%pw_grid%para%group%mepos == 0, &
664 native_grid_diagnostics)
665 IF (native_grid_diagnostics)
THEN
666 CALL print_virial_delta(
"static-coordinates", virial_xc - virial_before, &
667 rho_r(1)%pw_grid%para%group%mepos == 0)
668 virial_before = virial_xc
671 CALL build_smooth_partition_virial(virial_xc, features, particle_set, cell, rho_r, &
672 grid_weight_grad_t, atomic_grid_weight_grad_t)
673 IF (native_grid_diagnostics)
THEN
674 CALL print_virial_delta(
"smooth-partition", virial_xc - virial_before, &
675 rho_r(1)%pw_grid%para%group%mepos == 0)
676 virial_before = virial_xc
680 CALL omp_set_num_threads(omp_max_threads_restore)
682 density_grad, grad_grad, kin_grad, &
684 CALL timestop(phase_handle)
686 CALL timeset(
"skala_gpw_grad_release", phase_handle)
687 DEALLOCATE (density_grad, grad_grad, kin_grad)
689 CALL timestop(phase_handle)
692 CALL timeset(
"skala_gpw_cleanup", phase_handle)
697 CALL omp_set_num_threads(omp_max_threads_restore)
698 CALL timestop(phase_handle)
716 weights, pw_pool, particle_set, cell)
727 CHARACTER(len=default_path_length) :: model_path
728 INTEGER :: feature_begin, feature_end, feature_pos, i, iatom, j, k, local_row, &
729 native_grid_atom_partition, native_grid_cuda_device, natom, nspins, &
730 omp_max_threads_restore, row, selected_cuda_device, xc_deriv_method_id, xc_rho_smooth_id
731 INTEGER,
DIMENSION(2, 3) :: bo
732 LOGICAL :: lsd, native_grid_use_cuda
733 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: included
734 REAL(kind=
dp) :: exc, local_derivative
735 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: partition_weights
736 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: atom_coords_pbc
737 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
738 REAL(kind=
dp),
DIMENSION(3) :: grid_point
739 REAL(kind=
dp),
DIMENSION(:),
POINTER :: grid_weight_grad
746 cpassert(
ASSOCIATED(rho_r))
747 cpassert(
ASSOCIATED(rho_g))
748 cpassert(
ASSOCIATED(tau))
750 omp_max_threads_restore = omp_get_max_threads()
754 CALL get_skala_model_path(xc_section, model_path)
758 i_val=native_grid_cuda_device)
760 i_val=native_grid_atom_partition)
761 SELECT CASE (native_grid_atom_partition)
767 CALL cp_abort(__location__, &
768 "Unknown GAUXC%NATIVE_GRID_ATOM_PARTITION value.")
775 selected_cuda_device = configure_native_grid_cuda( &
776 native_grid_use_cuda, native_grid_cuda_device, rho_r(1)%pw_grid%para%group)
777 CALL ensure_model_loaded(model_path, selected_cuda_device, xc_section)
780 needs%rho_spin = .true.
781 needs%drho_spin = .true.
782 needs%tau_spin = .true.
793 rho_r(1)%pw_grid%bounds_local, &
798 xc_deriv_method_id, xc_rho_smooth_id, pw_pool)
801 requires_grad=.false., weights=weights, &
802 requires_coordinate_grad=.false., &
803 requires_stress_grad=.true., &
804 use_atom_chunks=.false., route_atom_chunks=.false., &
805 atom_partition=native_grid_atom_partition)
809 NULLIFY (grid_weight_grad)
813 natom =
SIZE(particle_set)
815 ALLOCATE (atom_coords_pbc(3, natom), included(natom), partition_weights(natom), &
816 dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
818 atom_coords_pbc(:, iatom) =
pbc(particle_set(iatom)%r, cell, positive_range=.true.)
822 bo = rho_r(1)%pw_grid%bounds_local
824 DO k = bo(1, 3), bo(2, 3)
825 DO j = bo(1, 2), bo(2, 2)
826 DO i = bo(1, 1), bo(2, 1)
827 local_row = local_row + 1
828 feature_begin = features%local_feature_offsets(local_row)
829 feature_end = features%local_feature_offsets(local_row + 1) - 1
830 local_derivative = 0.0_dp
832 cpassert(feature_end == feature_begin)
833 row = features%local_feature_rows(feature_begin)
834 local_derivative = grid_weight_grad(row)
836 grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
838 grid_point, atom_coords_pbc, cell, partition_weights, included, &
839 dweights_datom, dweights_dstrain)
840 cpassert(feature_end - feature_begin + 1 == count(included))
841 feature_pos = feature_begin
843 IF (.NOT. included(iatom)) cycle
844 row = features%local_feature_rows(feature_pos)
845 local_derivative = local_derivative + &
846 partition_weights(iatom)*grid_weight_grad(row)
847 feature_pos = feature_pos + 1
849 cpassert(feature_pos == feature_end + 1)
851 weight_deriv_r%array(i, j, k) = local_derivative
855 cpassert(local_row == features%nflat_local)
857 IF (
ALLOCATED(atom_coords_pbc))
THEN
858 DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, &
866 CALL omp_set_num_threads(omp_max_threads_restore)
893 rho, drho, tau, weights, lsd, nspins, na, nr, &
894 exc, vxc, vxg, vtau, energy_only, atom_force, atom_virial)
899 REAL(kind=
dp),
DIMENSION(3),
INTENT(IN) :: atom_coord
900 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: rho, tau, vxc, vtau
901 REAL(kind=
dp),
DIMENSION(:, :, :, :),
POINTER :: drho, vxg
902 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: weights
903 LOGICAL,
INTENT(IN) :: lsd
904 INTEGER,
INTENT(IN) :: nspins, na, nr
905 REAL(kind=
dp),
INTENT(OUT) :: exc
906 LOGICAL,
INTENT(IN),
OPTIONAL :: energy_only
907 REAL(kind=
dp),
DIMENSION(3),
INTENT(OUT), &
908 OPTIONAL :: atom_force
909 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(OUT), &
910 OPTIONAL :: atom_virial
912 CHARACTER(len=default_path_length) :: model_path
913 INTEGER :: ia, idir, ir, native_grid_cuda_device, &
914 jdir, nflat, omp_max_threads_restore, row, &
916 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:) :: atomic_grid_sizes
917 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:, :) :: atomic_grid_size_bound_shape
918 LOGICAL :: need_coord_grad, my_energy_only, native_grid_use_cuda
920 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: atomic_grid_weights, grid_weights
921 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: coarse_0_atomic_coords, density, &
923 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: grad
924 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad, density_grad, &
925 grid_coord_grad, kin_grad
926 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad
930 atomic_grid_sizes_t, &
931 atomic_grid_weights_t, &
933 coarse_0_atomic_coords_t, density_t, &
934 density_grad_t, exc_tensor, grad_t, &
935 grad_grad_t, grid_coord_grad_t, &
936 grid_coords_t, grid_weights_t, kin_t, &
939 cpassert(
ASSOCIATED(xc_section))
940 cpassert(
ASSOCIATED(grid_atom))
941 cpassert(
ASSOCIATED(rho))
942 cpassert(
ASSOCIATED(drho))
943 cpassert(
ASSOCIATED(tau))
944 omp_max_threads_restore = omp_get_max_threads()
946 my_energy_only = .false.
947 IF (
PRESENT(energy_only)) my_energy_only = energy_only
948 need_coord_grad =
PRESENT(atom_force) .OR.
PRESENT(atom_virial)
950 IF (
PRESENT(atom_force)) atom_force = 0.0_dp
951 IF (
PRESENT(atom_virial)) atom_virial = 0.0_dp
952 IF (.NOT. my_energy_only)
THEN
958 CALL get_skala_model_path(xc_section, model_path)
960 cpassert(
ASSOCIATED(gauxc_section))
963 i_val=native_grid_cuda_device)
965 selected_cuda_device = configure_native_grid_cuda( &
966 native_grid_use_cuda, native_grid_cuda_device, group)
967 CALL ensure_model_loaded(model_path, selected_cuda_device, xc_section)
970 ALLOCATE (density(nflat, 2), grad(nflat, 3, 2), kin(nflat, 2), &
971 grid_coords(3, nflat), grid_weights(nflat), &
972 atomic_grid_weights(nflat), atomic_grid_sizes(1), &
973 coarse_0_atomic_coords(3, 1), atomic_grid_size_bound_shape(0, nflat))
978 grid_weights = 0.0_dp
979 atomic_grid_weights = 0.0_dp
980 atomic_grid_sizes(1) = int(nflat, kind=
int_8)
981 atomic_grid_size_bound_shape = 0_int_8
982 coarse_0_atomic_coords(:, 1) = atom_coord
988 grid_coords(1, row) = atom_coord(1) + grid_atom%rad(ir)* &
989 grid_atom%sin_pol(ia)*grid_atom%cos_azi(ia)
990 grid_coords(2, row) = atom_coord(2) + grid_atom%rad(ir)* &
991 grid_atom%sin_pol(ia)*grid_atom%sin_azi(ia)
992 grid_coords(3, row) = atom_coord(3) + grid_atom%rad(ir)*grid_atom%cos_pol(ia)
993 grid_weights(row) = weights(ia, ir)
994 atomic_grid_weights(row) = weights(ia, ir)
995 IF (nspins == 1)
THEN
996 density(row, :) = 0.5_dp*rho(ia, ir, 1)
998 grad(row, idir, :) = 0.5_dp*drho(idir, ia, ir, 1)
1000 kin(row, :) = 0.5_dp*tau(ia, ir, 1)
1002 density(row, :) = rho(ia, ir, 1:2)
1004 grad(row, idir, :) = drho(idir, ia, ir, 1:2)
1006 kin(row, :) = tau(ia, ir, 1:2)
1020 atomic_grid_size_bound_shape)
1037 atomic_grid_size_bound_shape_t)
1041 CALL torch_dict_insert(inputs,
"coarse_0_atomic_coords", coarse_0_atomic_coords_t)
1045 IF (.NOT. my_energy_only)
THEN
1046 NULLIFY (atom_coord_grad, density_grad, grad_grad, grid_coord_grad, kin_grad)
1048 IF (need_coord_grad)
THEN
1053 IF (
PRESENT(atom_force))
THEN
1054 atom_force(:) = atom_coord_grad(:, 1)
1056 atom_force(:) = atom_force(:) + grid_coord_grad(:, row)
1059 IF (
PRESENT(atom_virial))
THEN
1063 tmp = grid_coord_grad(idir, row)*coarse_0_atomic_coords(jdir, 1)
1064 atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
1070 tmp = atom_coord_grad(idir, 1)*coarse_0_atomic_coords(jdir, 1)
1071 atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
1077 grad_grad_t, kin_grad_t)
1087 vxc(ia, ir, 1:2) = density_grad(row, 1:2)
1089 vxg(idir, ia, ir, 1:2) = grad_grad(row, idir, 1:2)
1091 vtau(ia, ir, 1:2) = kin_grad(row, 1:2)
1093 vxc(ia, ir, 1) = 0.5_dp*(density_grad(row, 1) + density_grad(row, 2))
1095 vxg(idir, ia, ir, 1) = &
1096 0.5_dp*(grad_grad(row, idir, 1) + grad_grad(row, idir, 2))
1098 vtau(ia, ir, 1) = 0.5_dp*(kin_grad(row, 1) + kin_grad(row, 2))
1106 IF (need_coord_grad)
THEN
1123 DEALLOCATE (atomic_grid_size_bound_shape, atomic_grid_sizes, atomic_grid_weights, &
1124 coarse_0_atomic_coords, density, grad, grid_coords, grid_weights, kin)
1126 CALL omp_set_num_threads(omp_max_threads_restore)
1152 grid_coords, grid_weights, atomic_grid_weights, &
1153 atomic_grid_sizes, atomic_coords, exc, &
1154 density_grad_out, grad_grad_out, kin_grad_out, &
1155 grid_coord_grad_out, grid_weight_grad_out, &
1156 atomic_grid_weight_grad_out, atom_coord_grad_out)
1160 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :),
INTENT(IN) :: density, grid_coords, &
1162 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :),
INTENT(IN) :: grad
1163 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:),
INTENT(IN) :: grid_weights, atomic_grid_weights
1164 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:),
INTENT(IN) :: atomic_grid_sizes
1165 REAL(kind=
dp),
INTENT(OUT) :: exc
1166 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :),
INTENT(OUT),
OPTIONAL :: density_grad_out, &
1168 grid_coord_grad_out, &
1170 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :),
INTENT(OUT),
OPTIONAL :: grad_grad_out
1171 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT),
OPTIONAL :: grid_weight_grad_out, &
1172 atomic_grid_weight_grad_out
1174 CHARACTER(len=default_path_length) :: model_path
1175 INTEGER :: atom_begin, atom_count, chunk_max_rows, chunk_row_count, chunk_row_start, &
1176 ichunk, local_natom, local_nrow, max_grid_size, native_grid_cuda_device, &
1177 nchunks, omp_max_threads_restore, phase_handle, selected_cuda_device
1178 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: chunk_atom_begin, chunk_atom_count, &
1179 chunk_row_begin, chunk_row_counts
1180 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:, :) :: atomic_grid_size_bound_shape
1181 LOGICAL :: active_rank, native_grid_atom_chunks, native_grid_use_cuda, &
1182 need_coordinate_derivatives, need_derivatives
1183 REAL(kind=
dp) :: chunk_exc
1184 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
1185 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad, density_grad, &
1186 grid_coord_grad, kin_grad
1187 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad
1191 atomic_grid_sizes_t, &
1192 atomic_grid_sizes_chunk_t, &
1193 atomic_grid_weight_grad_t, &
1194 atomic_grid_weights_chunk_t, &
1195 atom_coord_grad_t, atomic_coords_chunk_t, &
1196 density_chunk_t, density_grad_t, &
1197 exc_tensor, grad_chunk_t, grad_grad_t, &
1198 grid_coord_grad_t, grid_coords_chunk_t, &
1199 grid_weight_grad_t, grid_weights_chunk_t, &
1200 kin_chunk_t, kin_grad_t
1202 atomic_grid_weights_local_t, &
1203 density_local_t, grad_local_t, &
1204 grid_coords_local_t, grid_weights_local_t, &
1207 density_t, grad_t, grid_coords_t, &
1208 grid_weights_t, kin_t
1210 cpassert(
ASSOCIATED(xc_section))
1211 cpassert(
SIZE(density, 1) ==
SIZE(grid_weights))
1212 cpassert(
SIZE(density, 1) ==
SIZE(atomic_grid_weights))
1213 cpassert(
SIZE(density, 1) ==
SIZE(grid_coords, 2))
1214 cpassert(
SIZE(density, 1) ==
SIZE(grad, 1))
1215 cpassert(
SIZE(density, 1) ==
SIZE(kin, 1))
1216 cpassert(
SIZE(density, 2) == 2)
1217 cpassert(
SIZE(grad, 2) == 3)
1218 cpassert(
SIZE(grad, 3) == 2)
1219 cpassert(
SIZE(kin, 2) == 2)
1220 cpassert(
SIZE(atomic_grid_sizes) ==
SIZE(atomic_coords, 2))
1221 cpassert(sum(atomic_grid_sizes) == int(
SIZE(density, 1), kind=
int_8))
1222 need_derivatives =
PRESENT(density_grad_out)
1223 cpassert(
PRESENT(grad_grad_out) .EQV. need_derivatives)
1224 cpassert(
PRESENT(kin_grad_out) .EQV. need_derivatives)
1225 need_coordinate_derivatives =
PRESENT(grid_coord_grad_out)
1226 cpassert(
PRESENT(grid_weight_grad_out) .EQV. need_coordinate_derivatives)
1227 cpassert(
PRESENT(atomic_grid_weight_grad_out) .EQV. need_coordinate_derivatives)
1228 cpassert(
PRESENT(atom_coord_grad_out) .EQV. need_coordinate_derivatives)
1229 cpassert((.NOT. need_coordinate_derivatives) .OR. need_derivatives)
1230 omp_max_threads_restore = omp_get_max_threads()
1232 local_nrow =
SIZE(density, 1)
1233 local_natom =
SIZE(atomic_grid_sizes)
1234 active_rank = local_natom > 0
1235 cpassert(active_rank .EQV. (local_nrow > 0))
1237 CALL get_skala_model_path(xc_section, model_path)
1239 cpassert(
ASSOCIATED(gauxc_section))
1242 i_val=native_grid_cuda_device)
1244 l_val=native_grid_atom_chunks)
1246 i_val=chunk_max_rows)
1247 IF (chunk_max_rows < -1)
THEN
1248 CALL cp_abort(__location__, &
1249 "GAUXC%NATIVE_GRID_ATOM_CHUNK_MAX_ROWS must be -1, zero, or positive.")
1251 IF (.NOT. native_grid_atom_chunks) chunk_max_rows = 0
1252 IF (chunk_max_rows == -1)
THEN
1253 chunk_max_rows = auto_atom_composite_chunk_max_rows(atomic_grid_sizes, group)
1256 selected_cuda_device = configure_native_grid_cuda( &
1257 native_grid_use_cuda, native_grid_cuda_device, group)
1259 IF (active_rank)
THEN
1260 CALL timeset(
"skala_atom_tensor_setup", phase_handle)
1261 CALL ensure_model_loaded(model_path, selected_cuda_device, xc_section)
1262 CALL atom_composite_chunk_layout(atomic_grid_sizes, chunk_max_rows, &
1263 chunk_atom_begin, chunk_atom_count, &
1264 chunk_row_begin, chunk_row_counts)
1265 nchunks =
SIZE(chunk_atom_begin)
1266 cpassert(nchunks > 0)
1268 IF (native_grid_use_cuda)
THEN
1269 grid_coords_t => cached_atom_cuda_tensors%grid_coords_t
1270 grid_weights_t => cached_atom_cuda_tensors%grid_weights_t
1271 atomic_grid_weights_t => cached_atom_cuda_tensors%atomic_grid_weights_t
1272 atomic_coords_t => cached_atom_cuda_tensors%atomic_coords_t
1273 density_t => cached_atom_cuda_tensors%density_t
1274 grad_t => cached_atom_cuda_tensors%grad_t
1275 kin_t => cached_atom_cuda_tensors%kin_t
1277 grid_coords_t, grid_coords, need_coordinate_derivatives)
1279 grid_weights_t, grid_weights, need_coordinate_derivatives)
1281 atomic_grid_weights_t, atomic_grid_weights, need_coordinate_derivatives)
1283 atomic_coords_t, atomic_coords, need_coordinate_derivatives)
1288 grid_coords_t => grid_coords_local_t
1289 grid_weights_t => grid_weights_local_t
1290 atomic_grid_weights_t => atomic_grid_weights_local_t
1291 atomic_coords_t => atomic_coords_local_t
1292 density_t => density_local_t
1293 grad_t => grad_local_t
1294 kin_t => kin_local_t
1312 CALL timestop(phase_handle)
1314 DO ichunk = 1, nchunks
1315 atom_begin = chunk_atom_begin(ichunk)
1316 atom_count = chunk_atom_count(ichunk)
1317 chunk_row_start = chunk_row_begin(ichunk)
1318 chunk_row_count = chunk_row_counts(ichunk)
1319 max_grid_size = int(maxval(atomic_grid_sizes( &
1320 atom_begin:atom_begin + atom_count - 1)))
1321 ALLOCATE (atomic_grid_size_bound_shape(0, max_grid_size))
1322 atomic_grid_size_bound_shape = 0_int_8
1325 chunk_row_count, grid_coords_chunk_t)
1327 chunk_row_count, grid_weights_chunk_t)
1329 chunk_row_count, atomic_grid_weights_chunk_t)
1331 atom_count, atomic_grid_sizes_chunk_t)
1333 atom_count, atomic_coords_chunk_t)
1335 chunk_row_count, density_chunk_t)
1337 chunk_row_count, grad_chunk_t)
1339 chunk_row_count, kin_chunk_t)
1341 atomic_grid_size_bound_shape)
1347 CALL torch_dict_insert(inputs,
"atomic_grid_weights", atomic_grid_weights_chunk_t)
1350 atomic_grid_size_bound_shape_t)
1356 CALL timeset(
"skala_atom_torch_forward", phase_handle)
1358 exc_tensor, chunk_exc)
1359 CALL timestop(phase_handle)
1360 exc = exc + chunk_exc
1361 IF (need_derivatives)
THEN
1362 CALL timeset(
"skala_atom_torch_backward", phase_handle)
1364 CALL timestop(phase_handle)
1378 DEALLOCATE (atomic_grid_size_bound_shape)
1383 IF (need_derivatives)
THEN
1384 ALLOCATE (density_grad_out(local_nrow, 2), grad_grad_out(local_nrow, 3, 2), &
1385 kin_grad_out(local_nrow, 2))
1386 density_grad_out = 0.0_dp
1387 grad_grad_out = 0.0_dp
1388 kin_grad_out = 0.0_dp
1389 IF (active_rank)
THEN
1390 NULLIFY (density_grad, grad_grad, kin_grad)
1391 CALL timeset(
"skala_atom_grad_fetch", phase_handle)
1393 grad_grad_t, kin_grad_t)
1397 density_grad_out(:, :) = density_grad
1398 grad_grad_out(:, :, :) = grad_grad
1399 kin_grad_out(:, :) = kin_grad
1400 CALL timestop(phase_handle)
1403 IF (need_coordinate_derivatives)
THEN
1404 IF (active_rank)
CALL timeset(
"skala_atom_coord_grad_fetch", phase_handle)
1405 ALLOCATE (grid_coord_grad_out(3, local_nrow), grid_weight_grad_out(local_nrow), &
1406 atomic_grid_weight_grad_out(local_nrow), atom_coord_grad_out(3, local_natom))
1407 grid_coord_grad_out = 0.0_dp
1408 grid_weight_grad_out = 0.0_dp
1409 atomic_grid_weight_grad_out = 0.0_dp
1410 atom_coord_grad_out = 0.0_dp
1411 IF (active_rank)
THEN
1412 NULLIFY (atomic_grid_weight_grad, atom_coord_grad, grid_coord_grad, grid_weight_grad)
1421 grid_coord_grad_out(:, :) = grid_coord_grad
1422 grid_weight_grad_out(:) = grid_weight_grad
1423 atomic_grid_weight_grad_out(:) = atomic_grid_weight_grad
1424 atom_coord_grad_out(:, :) = atom_coord_grad
1429 CALL timestop(phase_handle)
1432 IF (active_rank)
THEN
1439 IF (active_rank)
THEN
1440 CALL timeset(
"skala_atom_tensor_release", phase_handle)
1441 IF (.NOT. native_grid_use_cuda)
THEN
1451 DEALLOCATE (chunk_atom_begin, chunk_atom_count, chunk_row_begin, chunk_row_counts)
1452 CALL timestop(phase_handle)
1455 CALL omp_set_num_threads(omp_max_threads_restore)
1465 FUNCTION auto_atom_composite_chunk_max_rows(atomic_grid_sizes, group)
RESULT(max_rows)
1466 INTEGER(KIND=int_8),
DIMENSION(:),
INTENT(IN) :: atomic_grid_sizes
1470 INTEGER :: local_max_atom_rows, local_natom, &
1471 local_padded_rows, max_rows
1473 local_padded_rows = 0
1474 local_natom =
SIZE(atomic_grid_sizes)
1475 IF (local_natom > 0)
THEN
1476 local_max_atom_rows = int(maxval(atomic_grid_sizes))
1477 IF (local_natom > atom_chunk_auto_max_rows .OR. &
1478 local_max_atom_rows > atom_chunk_auto_max_rows/local_natom)
THEN
1479 local_padded_rows = atom_chunk_auto_max_rows + 1
1481 local_padded_rows = local_natom*local_max_atom_rows
1484 CALL group%max(local_padded_rows)
1485 IF (local_padded_rows <= atom_chunk_auto_max_rows)
THEN
1489 max_rows = atom_chunk_auto_max_rows
1491 END FUNCTION auto_atom_composite_chunk_max_rows
1502 SUBROUTINE atom_composite_chunk_layout(atomic_grid_sizes, max_rows, atom_begin, atom_count, &
1503 row_begin, row_count)
1504 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:), &
1505 INTENT(IN) :: atomic_grid_sizes
1506 INTEGER,
INTENT(IN) :: max_rows
1507 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: atom_begin, atom_count, row_begin, &
1510 INTEGER :: atom_begin_tmp, atom_count_tmp, atom_rows, chunk_atoms, chunk_max_atom_rows, &
1511 iatom, insert_at, natom, nchunks, padded_rows_tmp, row_begin_tmp, row_count_tmp, rows, &
1513 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: padded_rows
1515 natom =
SIZE(atomic_grid_sizes)
1517 cpassert(all(atomic_grid_sizes > 0_int_8))
1518 IF (max_rows <= 0)
THEN
1519 ALLOCATE (atom_begin(1), atom_count(1), row_begin(1), row_count(1))
1521 atom_count(1) = natom
1523 row_count(1) = int(sum(atomic_grid_sizes))
1529 chunk_max_atom_rows = 0
1531 atom_rows = int(atomic_grid_sizes(iatom))
1532 IF (chunk_atoms > 0 .AND. &
1533 max(chunk_max_atom_rows, atom_rows) > max_rows/(chunk_atoms + 1))
THEN
1534 nchunks = nchunks + 1
1536 chunk_max_atom_rows = 0
1538 chunk_atoms = chunk_atoms + 1
1539 chunk_max_atom_rows = max(chunk_max_atom_rows, atom_rows)
1541 ALLOCATE (atom_begin(nchunks), atom_count(nchunks), row_begin(nchunks), row_count(nchunks))
1544 atom_begin(subchunk) = 1
1545 row_begin(subchunk) = 1
1547 chunk_max_atom_rows = 0
1550 atom_rows = int(atomic_grid_sizes(iatom))
1551 IF (chunk_atoms > 0 .AND. &
1552 max(chunk_max_atom_rows, atom_rows) > max_rows/(chunk_atoms + 1))
THEN
1553 atom_count(subchunk) = iatom - atom_begin(subchunk)
1554 row_count(subchunk) = rows
1555 subchunk = subchunk + 1
1556 atom_begin(subchunk) = iatom
1557 row_begin(subchunk) = row_begin(subchunk - 1) + row_count(subchunk - 1)
1559 chunk_max_atom_rows = 0
1562 chunk_atoms = chunk_atoms + 1
1563 chunk_max_atom_rows = max(chunk_max_atom_rows, atom_rows)
1564 rows = rows + atom_rows
1566 atom_count(subchunk) = natom - atom_begin(subchunk) + 1
1567 row_count(subchunk) = rows
1568 cpassert(subchunk == nchunks)
1570 ALLOCATE (padded_rows(nchunks))
1571 DO subchunk = 1, nchunks
1572 iatom = atom_begin(subchunk) + atom_count(subchunk) - 1
1573 padded_rows(subchunk) = atom_count(subchunk)* &
1574 int(maxval(atomic_grid_sizes(atom_begin(subchunk):iatom)))
1578 DO subchunk = 2, nchunks
1579 padded_rows_tmp = padded_rows(subchunk)
1580 atom_begin_tmp = atom_begin(subchunk)
1581 atom_count_tmp = atom_count(subchunk)
1582 row_begin_tmp = row_begin(subchunk)
1583 row_count_tmp = row_count(subchunk)
1584 insert_at = subchunk
1585 DO WHILE (insert_at > 1 .AND. padded_rows(insert_at - 1) < padded_rows_tmp)
1586 padded_rows(insert_at) = padded_rows(insert_at - 1)
1587 atom_begin(insert_at) = atom_begin(insert_at - 1)
1588 atom_count(insert_at) = atom_count(insert_at - 1)
1589 row_begin(insert_at) = row_begin(insert_at - 1)
1590 row_count(insert_at) = row_count(insert_at - 1)
1591 insert_at = insert_at - 1
1593 padded_rows(insert_at) = padded_rows_tmp
1594 atom_begin(insert_at) = atom_begin_tmp
1595 atom_count(insert_at) = atom_count_tmp
1596 row_begin(insert_at) = row_begin_tmp
1597 row_count(insert_at) = row_count_tmp
1599 DEALLOCATE (padded_rows)
1601 END SUBROUTINE atom_composite_chunk_layout
1610 SUBROUTINE add_explicit_coordinate_force(atom_force, features, atom_coord_grad_t, root_rank)
1611 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: atom_force
1614 LOGICAL,
INTENT(IN) :: root_rank
1616 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad
1618 NULLIFY (atom_coord_grad)
1622 cpassert(
SIZE(atom_force, 1) ==
SIZE(atom_coord_grad, 1))
1623 cpassert(
SIZE(atom_force, 2) ==
SIZE(atom_coord_grad, 2))
1624 atom_force(:, :) = atom_force(:, :) + atom_coord_grad(:, :)
1627 END SUBROUTINE add_explicit_coordinate_force
1639 SUBROUTINE add_smooth_partition_force(atom_force, features, particle_set, cell, rho_r, &
1640 grid_weight_grad_t, atomic_grid_weight_grad_t)
1641 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: atom_force
1647 atomic_grid_weight_grad_t
1649 INTEGER :: feature_begin, feature_end, feature_pos, &
1650 i, iatom, j, jatom, k, local_row, &
1652 INTEGER,
DIMENSION(2, 3) :: bo
1653 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: included
1654 REAL(kind=
dp) :: grid_base_weight, weight_grad
1655 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: weights
1656 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: atom_coords_pbc
1657 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
1658 REAL(kind=
dp),
DIMENSION(3) :: grid_point
1659 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
1661 NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
1663 CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
1667 natom =
SIZE(particle_set)
1668 cpassert(
SIZE(atom_force, 1) == 3)
1669 cpassert(
SIZE(atom_force, 2) == natom)
1670 ALLOCATE (atom_coords_pbc(3, natom), included(natom), weights(natom), &
1671 dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
1673 atom_coords_pbc(:, iatom) =
pbc(particle_set(iatom)%r, cell, positive_range=.true.)
1676 bo = rho_r(1)%pw_grid%bounds_local
1678 DO k = bo(1, 3), bo(2, 3)
1679 DO j = bo(1, 2), bo(2, 2)
1680 DO i = bo(1, 1), bo(2, 1)
1681 local_row = local_row + 1
1682 grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
1684 weights, included, dweights_datom, &
1686 feature_begin = features%local_feature_offsets(local_row)
1687 feature_end = features%local_feature_offsets(local_row + 1) - 1
1688 cpassert(feature_end - feature_begin + 1 == count(included))
1689 grid_base_weight = 0.0_dp
1690 DO feature_pos = feature_begin, feature_end
1691 row = features%local_feature_rows(feature_pos)
1692 grid_base_weight = grid_base_weight + features%grid_weights(row)
1694 feature_pos = feature_begin
1696 IF (.NOT. included(iatom)) cycle
1697 row = features%local_feature_rows(feature_pos)
1698 weight_grad = grid_base_weight*grid_weight_grad(row) + &
1699 rho_r(1)%pw_grid%dvol*atomic_grid_weight_grad(row)* &
1702 atom_force(:, jatom) = atom_force(:, jatom) + &
1703 weight_grad*dweights_datom(:, jatom, iatom)
1705 feature_pos = feature_pos + 1
1707 cpassert(feature_pos == feature_end + 1)
1711 cpassert(local_row == features%nflat_local)
1713 DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, weights)
1717 END SUBROUTINE add_smooth_partition_force
1729 SUBROUTINE build_smooth_partition_virial(virial_xc, features, particle_set, cell, rho_r, &
1730 grid_weight_grad_t, atomic_grid_weight_grad_t)
1731 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
1737 atomic_grid_weight_grad_t
1739 INTEGER :: feature_begin, feature_end, feature_pos, &
1740 i, iatom, idir, j, jdir, k, local_row, &
1742 INTEGER,
DIMENSION(2, 3) :: bo
1743 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: included
1744 REAL(kind=
dp) :: grid_base_weight, tmp, weight_grad
1745 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: weights
1746 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: atom_coords_pbc
1747 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
1748 REAL(kind=
dp),
DIMENSION(3) :: grid_point
1749 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
1751 NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
1753 CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
1757 natom =
SIZE(particle_set)
1758 ALLOCATE (atom_coords_pbc(3, natom), included(natom), weights(natom), &
1759 dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
1761 atom_coords_pbc(:, iatom) =
pbc(particle_set(iatom)%r, cell, positive_range=.true.)
1764 bo = rho_r(1)%pw_grid%bounds_local
1766 DO k = bo(1, 3), bo(2, 3)
1767 DO j = bo(1, 2), bo(2, 2)
1768 DO i = bo(1, 1), bo(2, 1)
1769 local_row = local_row + 1
1770 grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
1772 weights, included, dweights_datom, &
1774 feature_begin = features%local_feature_offsets(local_row)
1775 feature_end = features%local_feature_offsets(local_row + 1) - 1
1776 cpassert(feature_end - feature_begin + 1 == count(included))
1777 grid_base_weight = 0.0_dp
1778 DO feature_pos = feature_begin, feature_end
1779 row = features%local_feature_rows(feature_pos)
1780 grid_base_weight = grid_base_weight + features%grid_weights(row)
1782 feature_pos = feature_begin
1784 IF (.NOT. included(iatom)) cycle
1785 row = features%local_feature_rows(feature_pos)
1786 weight_grad = grid_base_weight*grid_weight_grad(row) + &
1787 rho_r(1)%pw_grid%dvol*atomic_grid_weight_grad(row)* &
1791 tmp = weight_grad*dweights_dstrain(idir, jdir, iatom)
1792 virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
1793 IF (idir /= jdir) virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
1796 feature_pos = feature_pos + 1
1798 cpassert(feature_pos == feature_end + 1)
1802 cpassert(local_row == features%nflat_local)
1804 DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, weights)
1808 END SUBROUTINE build_smooth_partition_virial
1816 FUNCTION native_grid_coordinate(pw_grid, index)
RESULT(coord)
1818 INTEGER,
DIMENSION(3),
INTENT(IN) :: index
1819 REAL(kind=
dp),
DIMENSION(3) :: coord
1821 INTEGER,
DIMENSION(3) :: relative_index
1823 relative_index = index - pw_grid%bounds(1, :)
1824 coord = real(relative_index(1), kind=
dp)*pw_grid%dh(:, 1) + &
1825 REAL(relative_index(2), kind=
dp)*pw_grid%dh(:, 2) + &
1826 REAL(relative_index(3), kind=
dp)*pw_grid%dh(:, 3)
1828 END FUNCTION native_grid_coordinate
1842 SUBROUTINE evaluate_atom_subchunks(features, group, max_rows, compute_grads, exc, &
1843 density_grad, grad_grad, kin_grad, collapse_spin_grads)
1847 INTEGER,
INTENT(IN) :: max_rows
1848 LOGICAL,
INTENT(IN) :: compute_grads, collapse_spin_grads
1849 REAL(kind=
dp),
INTENT(OUT) :: exc
1850 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
1851 INTENT(OUT) :: density_grad, kin_grad
1852 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
1853 INTENT(OUT) :: grad_grad
1855 INTEGER :: isubchunk, nroute_grad_per_point, &
1856 nroute_recv_points, nroute_send_points, &
1857 nsubchunks, phase_handle, subphase_handle
1858 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: route_grad_return_recv_counts, &
1859 route_grad_return_recv_displs, &
1860 route_grad_return_send_counts, &
1861 route_grad_return_send_displs, &
1862 subchunk_atom_begin, &
1863 subchunk_atom_count, &
1864 subchunk_row_begin, &
1866 REAL(kind=
dp) :: subchunk_exc
1867 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: recv_grad_buffer, send_grad_buffer
1871 cpassert(features%uses_atom_chunks)
1872 cpassert(max_rows > 0)
1874 subchunk_row_begin, subchunk_row_count)
1875 nsubchunks =
SIZE(subchunk_atom_begin)
1878 IF (compute_grads)
THEN
1879 cpassert(features%uses_atom_chunk_routing)
1880 nroute_recv_points = sum(features%route_point_recv_counts)
1881 nroute_send_points =
SIZE(features%route_send_local_rows)
1882 cpassert(sum(features%route_point_send_counts) == nroute_send_points)
1883 cpassert(
SIZE(features%route_chunk_offsets) == nroute_recv_points + 1)
1884 nroute_grad_per_point = ngrad_per_point
1885 IF (collapse_spin_grads) nroute_grad_per_point = ncollapsed_grad_per_point
1886 ALLOCATE (send_grad_buffer(max(1, nroute_grad_per_point*nroute_recv_points)), &
1887 recv_grad_buffer(max(1, nroute_grad_per_point*nroute_send_points)), &
1888 route_grad_return_send_counts(
SIZE(features%route_point_recv_counts)), &
1889 route_grad_return_send_displs(
SIZE(features%route_point_recv_displs)), &
1890 route_grad_return_recv_counts(
SIZE(features%route_point_send_counts)), &
1891 route_grad_return_recv_displs(
SIZE(features%route_point_send_displs)))
1892 route_grad_return_send_counts(:) = &
1893 nroute_grad_per_point*features%route_point_recv_counts
1894 route_grad_return_send_displs(:) = &
1895 nroute_grad_per_point*features%route_point_recv_displs
1896 route_grad_return_recv_counts(:) = &
1897 nroute_grad_per_point*features%route_point_send_counts
1898 route_grad_return_recv_displs(:) = &
1899 nroute_grad_per_point*features%route_point_send_displs
1902 CALL timeset(
"skala_gpw_atom_subchunks", phase_handle)
1903 DO isubchunk = 1, nsubchunks
1904 CALL timeset(
"skala_gpw_atom_subchunk_build", subphase_handle)
1906 subchunk_atom_begin(isubchunk), &
1907 subchunk_atom_count(isubchunk), &
1908 subchunk_row_begin(isubchunk), &
1909 subchunk_row_count(isubchunk), &
1911 CALL timestop(subphase_handle)
1912 CALL timeset(
"skala_gpw_atom_subchunk_forward", subphase_handle)
1914 subchunk%grid_weights_t, subchunk_exc_tensor, &
1916 CALL timestop(subphase_handle)
1917 exc = exc + subchunk_exc
1918 IF (compute_grads)
THEN
1919 CALL timeset(
"skala_gpw_atom_subchunk_backward", subphase_handle)
1921 CALL timestop(subphase_handle)
1923 CALL timeset(
"skala_gpw_atom_subchunk_release", subphase_handle)
1926 CALL timestop(subphase_handle)
1928 IF (compute_grads .AND. features%chunk_feature_count > 0)
THEN
1929 CALL timeset(
"skala_gpw_atom_subchunk_grad_pack", subphase_handle)
1930 CALL pack_atom_chunk_grads(features, send_grad_buffer, .true., collapse_spin_grads)
1931 CALL timestop(subphase_handle)
1933 CALL timestop(phase_handle)
1935 IF (compute_grads)
THEN
1936 CALL timeset(
"skala_gpw_grad_route_comm", phase_handle)
1937 CALL group%alltoall(send_grad_buffer, route_grad_return_send_counts, &
1938 route_grad_return_send_displs, recv_grad_buffer, &
1939 route_grad_return_recv_counts, route_grad_return_recv_displs)
1940 CALL timestop(phase_handle)
1942 CALL timeset(
"skala_gpw_grad_route_scatter", phase_handle)
1943 CALL scatter_routed_atom_chunk_grads(features, recv_grad_buffer, collapse_spin_grads, &
1944 density_grad, grad_grad, kin_grad)
1945 CALL timestop(phase_handle)
1947 DEALLOCATE (recv_grad_buffer, route_grad_return_recv_counts, &
1948 route_grad_return_recv_displs, route_grad_return_send_counts, &
1949 route_grad_return_send_displs, send_grad_buffer)
1951 DEALLOCATE (subchunk_atom_begin, subchunk_atom_count, subchunk_row_begin, subchunk_row_count)
1953 END SUBROUTINE evaluate_atom_subchunks
1961 FUNCTION auto_atom_chunk_max_rows(features, group)
RESULT(max_rows)
1967 INTEGER :: local_rows_max, target_rows
1969 local_rows_max = features%chunk_feature_count
1970 CALL group%max(local_rows_max)
1971 IF (local_rows_max <= 0)
THEN
1976 IF (group%num_pe > 1)
THEN
1977 target_rows = ceiling(real(local_rows_max, kind=
dp)/2.0_dp)
1978 max_rows = atom_chunk_auto_row_quantum* &
1979 ((target_rows + atom_chunk_auto_row_quantum - 1)/atom_chunk_auto_row_quantum)
1981 target_rows = nint(real(local_rows_max, kind=
dp)/4.0_dp)
1982 max_rows = atom_chunk_auto_row_quantum* &
1983 max(1, nint(real(target_rows, kind=
dp)/ &
1984 REAL(atom_chunk_auto_row_quantum, kind=
dp)))
1986 max_rows = max(atom_chunk_auto_min_rows, min(atom_chunk_auto_max_rows, max_rows))
1988 END FUNCTION auto_atom_chunk_max_rows
1997 SUBROUTINE fetch_local_feature_grads(features, density_grad, grad_grad, kin_grad)
1999 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2000 INTENT(OUT) :: density_grad
2001 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2002 INTENT(OUT) :: grad_grad
2003 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2004 INTENT(OUT) :: kin_grad
2006 INTEGER :: feature_pos, i, j, k, local_row, row
2007 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: density_grad_all, kin_grad_all
2008 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad_all
2011 NULLIFY (density_grad_all, grad_grad_all, kin_grad_all)
2012 CALL get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2013 density_grad_all, grad_grad_all, kin_grad_all)
2014 cpassert(
SIZE(density_grad_all, 1) == features%nflat)
2015 cpassert(
SIZE(density_grad_all, 2) == 2)
2016 cpassert(
SIZE(grad_grad_all, 1) == features%nflat)
2017 cpassert(
SIZE(grad_grad_all, 2) == 3)
2018 cpassert(
SIZE(grad_grad_all, 3) == 2)
2019 cpassert(
SIZE(kin_grad_all, 1) == features%nflat)
2020 cpassert(
SIZE(kin_grad_all, 2) == 2)
2022 ALLOCATE (density_grad(features%nflat_local, 2), &
2023 grad_grad(features%nflat_local, 3, 2), &
2024 kin_grad(features%nflat_local, 2))
2025 density_grad = 0.0_dp
2029 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2030 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2031 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2032 local_row = local_row + 1
2033 DO feature_pos = features%local_feature_offsets(local_row), &
2034 features%local_feature_offsets(local_row + 1) - 1
2035 row = features%local_feature_rows(feature_pos)
2036 cpassert(row >= 1 .AND. row <= features%nflat)
2037 density_grad(local_row, :) = density_grad(local_row, :) + &
2038 density_grad_all(row, :)
2039 grad_grad(local_row, :, :) = grad_grad(local_row, :, :) + &
2040 grad_grad_all(row, :, :)
2041 kin_grad(local_row, :) = kin_grad(local_row, :) + kin_grad_all(row, :)
2046 cpassert(local_row == features%nflat_local)
2052 END SUBROUTINE fetch_local_feature_grads
2061 SUBROUTINE pack_atom_chunk_grads(features, TARGET, route_to_return_positions, &
2062 collapse_spin_grads)
2064 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
2065 INTENT(INOUT) ::
target
2066 LOGICAL,
INTENT(IN) :: route_to_return_positions
2067 LOGICAL,
INTENT(IN),
OPTIONAL :: collapse_spin_grads
2069 INTEGER :: base, feature_pos, irow, &
2070 ngrad_buffer_per_point, point_pos, &
2072 LOGICAL :: my_collapse_spin_grads
2073 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: chunk_density_grad, chunk_kin_grad
2074 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: chunk_grad_grad
2077 my_collapse_spin_grads = .false.
2078 IF (
PRESENT(collapse_spin_grads)) my_collapse_spin_grads = collapse_spin_grads
2079 ngrad_buffer_per_point = ngrad_per_point
2080 IF (my_collapse_spin_grads) ngrad_buffer_per_point = ncollapsed_grad_per_point
2082 NULLIFY (chunk_density_grad, chunk_grad_grad, chunk_kin_grad)
2083 CALL get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2084 chunk_density_grad, chunk_grad_grad, chunk_kin_grad)
2085 cpassert(mod(
SIZE(
TARGET), ngrad_buffer_per_point) == 0)
2086 target_points =
SIZE(
TARGET)/ngrad_buffer_per_point
2087 cpassert(
SIZE(chunk_density_grad, 1) == features%chunk_feature_count)
2088 cpassert(
SIZE(chunk_grad_grad, 1) == features%chunk_feature_count)
2089 cpassert(
SIZE(chunk_grad_grad, 2) == 3)
2090 cpassert(
SIZE(chunk_kin_grad, 1) == features%chunk_feature_count)
2091 IF (features%uses_collapsed_rks_dynamic)
THEN
2092 cpassert(my_collapse_spin_grads)
2093 cpassert(
SIZE(chunk_density_grad, 2) == 1)
2094 cpassert(
SIZE(chunk_grad_grad, 3) == 1)
2095 cpassert(
SIZE(chunk_kin_grad, 2) == 1)
2097 cpassert(
SIZE(chunk_density_grad, 2) == 2)
2098 cpassert(
SIZE(chunk_grad_grad, 3) == 2)
2099 cpassert(
SIZE(chunk_kin_grad, 2) == 2)
2102 IF (route_to_return_positions)
THEN
2103 cpassert(target_points ==
SIZE(features%route_chunk_offsets) - 1)
2108 DO point_pos = 1, target_points
2109 base = ngrad_buffer_per_point*(point_pos - 1)
2110 target(base + 1:base + ngrad_buffer_per_point) = 0.0_dp
2111 DO feature_pos = features%route_chunk_offsets(point_pos), &
2112 features%route_chunk_offsets(point_pos + 1) - 1
2113 irow = features%route_chunk_rows(feature_pos)
2114 cpassert(irow >= 1 .AND. irow <= features%chunk_feature_count)
2115 IF (my_collapse_spin_grads)
THEN
2116 IF (features%uses_collapsed_rks_dynamic)
THEN
2117 target(base + 1) = target(base + 1) + &
2118 0.5_dp*chunk_density_grad(irow, 1)
2119 target(base + 2) = target(base + 2) + &
2120 0.5_dp*chunk_grad_grad(irow, 1, 1)
2121 target(base + 3) = target(base + 3) + &
2122 0.5_dp*chunk_grad_grad(irow, 2, 1)
2123 target(base + 4) = target(base + 4) + &
2124 0.5_dp*chunk_grad_grad(irow, 3, 1)
2125 target(base + 5) = target(base + 5) + &
2126 0.5_dp*chunk_kin_grad(irow, 1)
2128 target(base + 1) = target(base + 1) + &
2129 0.5_dp*(chunk_density_grad(irow, 1) + &
2130 chunk_density_grad(irow, 2))
2131 target(base + 2) = target(base + 2) + &
2132 0.5_dp*(chunk_grad_grad(irow, 1, 1) + &
2133 chunk_grad_grad(irow, 1, 2))
2134 target(base + 3) = target(base + 3) + &
2135 0.5_dp*(chunk_grad_grad(irow, 2, 1) + &
2136 chunk_grad_grad(irow, 2, 2))
2137 target(base + 4) = target(base + 4) + &
2138 0.5_dp*(chunk_grad_grad(irow, 3, 1) + &
2139 chunk_grad_grad(irow, 3, 2))
2140 target(base + 5) = target(base + 5) + &
2141 0.5_dp*(chunk_kin_grad(irow, 1) + &
2142 chunk_kin_grad(irow, 2))
2145 target(base + 1:base + 2) = target(base + 1:base + 2) + &
2146 chunk_density_grad(irow, :)
2147 target(base + 3) = target(base + 3) + chunk_grad_grad(irow, 1, 1)
2148 target(base + 4) = target(base + 4) + chunk_grad_grad(irow, 2, 1)
2149 target(base + 5) = target(base + 5) + chunk_grad_grad(irow, 3, 1)
2150 target(base + 6) = target(base + 6) + chunk_grad_grad(irow, 1, 2)
2151 target(base + 7) = target(base + 7) + chunk_grad_grad(irow, 2, 2)
2152 target(base + 8) = target(base + 8) + chunk_grad_grad(irow, 3, 2)
2153 target(base + 9:base + 10) = target(base + 9:base + 10) + &
2154 chunk_kin_grad(irow, :)
2160 cpassert(target_points >= features%chunk_feature_count)
2165 DO irow = 1, features%chunk_feature_count
2166 base = ngrad_buffer_per_point*(irow - 1)
2167 IF (my_collapse_spin_grads)
THEN
2168 IF (features%uses_collapsed_rks_dynamic)
THEN
2169 target(base + 1) = 0.5_dp*chunk_density_grad(irow, 1)
2170 target(base + 2) = 0.5_dp*chunk_grad_grad(irow, 1, 1)
2171 target(base + 3) = 0.5_dp*chunk_grad_grad(irow, 2, 1)
2172 target(base + 4) = 0.5_dp*chunk_grad_grad(irow, 3, 1)
2173 target(base + 5) = 0.5_dp*chunk_kin_grad(irow, 1)
2175 target(base + 1) = 0.5_dp*(chunk_density_grad(irow, 1) + &
2176 chunk_density_grad(irow, 2))
2177 target(base + 2) = 0.5_dp*(chunk_grad_grad(irow, 1, 1) + &
2178 chunk_grad_grad(irow, 1, 2))
2179 target(base + 3) = 0.5_dp*(chunk_grad_grad(irow, 2, 1) + &
2180 chunk_grad_grad(irow, 2, 2))
2181 target(base + 4) = 0.5_dp*(chunk_grad_grad(irow, 3, 1) + &
2182 chunk_grad_grad(irow, 3, 2))
2183 target(base + 5) = 0.5_dp*(chunk_kin_grad(irow, 1) + &
2184 chunk_kin_grad(irow, 2))
2187 target(base + 1:base + 2) = chunk_density_grad(irow, :)
2188 target(base + 3) = chunk_grad_grad(irow, 1, 1)
2189 target(base + 4) = chunk_grad_grad(irow, 2, 1)
2190 target(base + 5) = chunk_grad_grad(irow, 3, 1)
2191 target(base + 6) = chunk_grad_grad(irow, 1, 2)
2192 target(base + 7) = chunk_grad_grad(irow, 2, 2)
2193 target(base + 8) = chunk_grad_grad(irow, 3, 2)
2194 target(base + 9:base + 10) = chunk_kin_grad(irow, :)
2204 END SUBROUTINE pack_atom_chunk_grads
2215 SUBROUTINE scatter_routed_atom_chunk_grads(features, recv_grad_buffer, collapse_spin_grads, &
2216 density_grad, grad_grad, kin_grad)
2218 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: recv_grad_buffer
2219 LOGICAL,
INTENT(IN) :: collapse_spin_grads
2220 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2221 INTENT(OUT) :: density_grad
2222 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2223 INTENT(OUT) :: grad_grad
2224 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2225 INTENT(OUT) :: kin_grad
2227 INTEGER :: base, local_row, nflat_local, &
2228 nroute_grad_per_point, nroute_points, &
2229 point_pos, row_route_pos
2231 nflat_local = features%nflat_local
2232 nroute_points =
SIZE(features%route_send_local_rows)
2233 nroute_grad_per_point = ngrad_per_point
2234 IF (collapse_spin_grads) nroute_grad_per_point = ncollapsed_grad_per_point
2235 cpassert(
SIZE(recv_grad_buffer) >= nroute_grad_per_point*nroute_points)
2236 ALLOCATE (density_grad(nflat_local, 2), grad_grad(nflat_local, 3, 2), &
2237 kin_grad(nflat_local, 2))
2243 DO local_row = 1, nflat_local
2244 density_grad(local_row, :) = 0.0_dp
2245 grad_grad(local_row, :, :) = 0.0_dp
2246 kin_grad(local_row, :) = 0.0_dp
2247 DO row_route_pos = features%route_row_offsets(local_row), &
2248 features%route_row_offsets(local_row + 1) - 1
2249 point_pos = features%route_row_positions(row_route_pos)
2250 cpassert(point_pos >= 1 .AND. point_pos <= nroute_points)
2251 base = nroute_grad_per_point*(point_pos - 1)
2252 IF (collapse_spin_grads)
THEN
2253 density_grad(local_row, :) = density_grad(local_row, :) + &
2254 recv_grad_buffer(base + 1)
2255 grad_grad(local_row, 1, :) = grad_grad(local_row, 1, :) + &
2256 recv_grad_buffer(base + 2)
2257 grad_grad(local_row, 2, :) = grad_grad(local_row, 2, :) + &
2258 recv_grad_buffer(base + 3)
2259 grad_grad(local_row, 3, :) = grad_grad(local_row, 3, :) + &
2260 recv_grad_buffer(base + 4)
2261 kin_grad(local_row, :) = kin_grad(local_row, :) + recv_grad_buffer(base + 5)
2263 density_grad(local_row, :) = density_grad(local_row, :) + &
2264 recv_grad_buffer(base + 1:base + 2)
2265 grad_grad(local_row, 1, 1) = grad_grad(local_row, 1, 1) + &
2266 recv_grad_buffer(base + 3)
2267 grad_grad(local_row, 2, 1) = grad_grad(local_row, 2, 1) + &
2268 recv_grad_buffer(base + 4)
2269 grad_grad(local_row, 3, 1) = grad_grad(local_row, 3, 1) + &
2270 recv_grad_buffer(base + 5)
2271 grad_grad(local_row, 1, 2) = grad_grad(local_row, 1, 2) + &
2272 recv_grad_buffer(base + 6)
2273 grad_grad(local_row, 2, 2) = grad_grad(local_row, 2, 2) + &
2274 recv_grad_buffer(base + 7)
2275 grad_grad(local_row, 3, 2) = grad_grad(local_row, 3, 2) + &
2276 recv_grad_buffer(base + 8)
2277 kin_grad(local_row, :) = kin_grad(local_row, :) + &
2278 recv_grad_buffer(base + 9:base + 10)
2284 END SUBROUTINE scatter_routed_atom_chunk_grads
2296 SUBROUTINE get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2297 density_grad, grad_grad, kin_grad)
2299 TYPE(
torch_tensor_type),
INTENT(INOUT) :: density_grad_t, grad_grad_t, kin_grad_t
2300 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: density_grad
2301 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad
2302 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: kin_grad
2304 NULLIFY (density_grad, grad_grad, kin_grad)
2306 density_grad_t, grad_grad_t, kin_grad_t)
2311 END SUBROUTINE get_feature_grad_views
2321 SUBROUTINE fetch_and_gather_atom_chunk_grads(features, group, density_grad, grad_grad, &
2326 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2327 INTENT(OUT) :: density_grad, kin_grad
2328 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2329 INTENT(OUT) :: grad_grad
2331 INTEGER :: base, feature_pos, i, j, k, local_row, &
2332 nflat_local, nroute_grad_per_point, &
2333 nroute_recv_points, nroute_send_points, &
2335 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: route_grad_return_recv_counts, &
2336 route_grad_return_recv_displs, &
2337 route_grad_return_send_counts, &
2338 route_grad_return_send_displs
2339 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: chunk_grad_buffer, global_grad_buffer, &
2340 recv_grad_buffer, send_grad_buffer
2342 cpassert(features%uses_atom_chunks)
2344 nflat_local = features%nflat_local
2345 IF (features%uses_atom_chunk_routing)
THEN
2346 nroute_recv_points = sum(features%route_point_recv_counts)
2347 nroute_send_points =
SIZE(features%route_send_local_rows)
2348 cpassert(sum(features%route_point_send_counts) == nroute_send_points)
2349 cpassert(
SIZE(features%route_chunk_offsets) == nroute_recv_points + 1)
2351 nroute_grad_per_point = ngrad_per_point
2352 IF (features%uses_collapsed_rks_dynamic)
THEN
2353 nroute_grad_per_point = ncollapsed_grad_per_point
2355 ALLOCATE (send_grad_buffer(max(1, nroute_grad_per_point*nroute_recv_points)), &
2356 recv_grad_buffer(max(1, nroute_grad_per_point*nroute_send_points)), &
2357 route_grad_return_send_counts(
SIZE(features%route_point_recv_counts)), &
2358 route_grad_return_send_displs(
SIZE(features%route_point_recv_displs)), &
2359 route_grad_return_recv_counts(
SIZE(features%route_point_send_counts)), &
2360 route_grad_return_recv_displs(
SIZE(features%route_point_send_displs)))
2361 route_grad_return_send_counts(:) = &
2362 nroute_grad_per_point*features%route_point_recv_counts
2363 route_grad_return_send_displs(:) = &
2364 nroute_grad_per_point*features%route_point_recv_displs
2365 route_grad_return_recv_counts(:) = &
2366 nroute_grad_per_point*features%route_point_send_counts
2367 route_grad_return_recv_displs(:) = &
2368 nroute_grad_per_point*features%route_point_send_displs
2370 IF (features%chunk_feature_count > 0)
THEN
2371 CALL timeset(
"skala_gpw_grad_torch_pack", phase_handle)
2372 CALL pack_atom_chunk_grads(features, send_grad_buffer, .true., &
2373 features%uses_collapsed_rks_dynamic)
2374 CALL timestop(phase_handle)
2377 CALL timeset(
"skala_gpw_grad_route_comm", phase_handle)
2378 CALL group%alltoall(send_grad_buffer, route_grad_return_send_counts, &
2379 route_grad_return_send_displs, recv_grad_buffer, &
2380 route_grad_return_recv_counts, route_grad_return_recv_displs)
2381 CALL timestop(phase_handle)
2383 CALL timeset(
"skala_gpw_grad_route_scatter", phase_handle)
2384 CALL scatter_routed_atom_chunk_grads(features, recv_grad_buffer, &
2385 features%uses_collapsed_rks_dynamic, &
2386 density_grad, grad_grad, kin_grad)
2387 CALL timestop(phase_handle)
2389 DEALLOCATE (recv_grad_buffer, route_grad_return_recv_counts, &
2390 route_grad_return_recv_displs, route_grad_return_send_counts, &
2391 route_grad_return_send_displs, send_grad_buffer)
2393 ALLOCATE (chunk_grad_buffer(max(1, ngrad_per_point*features%chunk_feature_count)), &
2394 global_grad_buffer(ngrad_per_point*features%nflat))
2395 IF (features%chunk_feature_count > 0)
THEN
2396 CALL timeset(
"skala_gpw_grad_torch_pack", phase_handle)
2397 CALL pack_atom_chunk_grads(features, chunk_grad_buffer, .false.)
2398 CALL timestop(phase_handle)
2401 CALL timeset(
"skala_gpw_grad_allgatherv", phase_handle)
2402 CALL group%allgatherv(chunk_grad_buffer, global_grad_buffer, &
2403 features%chunk_grad_counts, features%chunk_grad_displs)
2404 CALL timestop(phase_handle)
2406 CALL timeset(
"skala_gpw_grad_scatter", phase_handle)
2407 ALLOCATE (density_grad(nflat_local, 2), grad_grad(nflat_local, 3, 2), &
2408 kin_grad(nflat_local, 2))
2409 density_grad = 0.0_dp
2413 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2414 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2415 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2416 local_row = local_row + 1
2417 DO feature_pos = features%local_feature_offsets(local_row), &
2418 features%local_feature_offsets(local_row + 1) - 1
2419 row = features%local_feature_rows(feature_pos)
2420 cpassert(row >= 1 .AND. row <= features%nflat)
2421 base = ngrad_per_point*(row - 1)
2422 density_grad(local_row, :) = density_grad(local_row, :) + &
2423 global_grad_buffer(base + 1:base + 2)
2424 grad_grad(local_row, 1, 1) = grad_grad(local_row, 1, 1) + &
2425 global_grad_buffer(base + 3)
2426 grad_grad(local_row, 2, 1) = grad_grad(local_row, 2, 1) + &
2427 global_grad_buffer(base + 4)
2428 grad_grad(local_row, 3, 1) = grad_grad(local_row, 3, 1) + &
2429 global_grad_buffer(base + 5)
2430 grad_grad(local_row, 1, 2) = grad_grad(local_row, 1, 2) + &
2431 global_grad_buffer(base + 6)
2432 grad_grad(local_row, 2, 2) = grad_grad(local_row, 2, 2) + &
2433 global_grad_buffer(base + 7)
2434 grad_grad(local_row, 3, 2) = grad_grad(local_row, 3, 2) + &
2435 global_grad_buffer(base + 8)
2436 kin_grad(local_row, :) = kin_grad(local_row, :) + &
2437 global_grad_buffer(base + 9:base + 10)
2442 CALL timestop(phase_handle)
2443 DEALLOCATE (chunk_grad_buffer, global_grad_buffer)
2447 END SUBROUTINE fetch_and_gather_atom_chunk_grads
2456 SUBROUTINE build_virial_from_feature_grads(virial_xc, rho_set, rho_r, grad_grad)
2457 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
2460 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: grad_grad
2462 INTEGER :: i, idir, ipt, ispin, j, jdir, k, nspins
2463 INTEGER,
DIMENSION(2, 3) :: bo
2464 REAL(kind=
dp) :: grad_i, tmp
2467 nspins =
SIZE(rho_r)
2468 bo = rho_r(1)%pw_grid%bounds_local
2471 IF (nspins == 1)
THEN
2473 DO k = bo(1, 3), bo(2, 3)
2474 DO j = bo(1, 2), bo(2, 2)
2475 DO i = bo(1, 1), bo(2, 1)
2478 grad_i = 0.5_dp*(grad_grad(ipt, idir, 1) + grad_grad(ipt, idir, 2))
2480 tmp = -grad_i*drho(jdir)%array(i, j, k)
2481 virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2489 DO k = bo(1, 3), bo(2, 3)
2490 DO j = bo(1, 2), bo(2, 2)
2491 DO i = bo(1, 1), bo(2, 1)
2497 IF (ispin == 1)
THEN
2498 tmp = tmp - grad_grad(ipt, idir, ispin)*drhoa(jdir)%array(i, j, k)
2500 tmp = tmp - grad_grad(ipt, idir, ispin)*drhob(jdir)%array(i, j, k)
2503 virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2511 END SUBROUTINE build_virial_from_feature_grads
2519 SUBROUTINE print_virial_delta(label, delta, root_rank)
2520 CHARACTER(LEN=*),
INTENT(IN) :: label
2521 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(IN) :: delta
2522 LOGICAL,
INTENT(IN) :: root_rank
2526 IF (.NOT. root_rank)
RETURN
2529 WRITE (iw,
"(T2,A,1X,A)")
"SKALA_GPW| XC virial contribution", trim(label)
2531 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW|", delta(i, 1:3)
2534 END SUBROUTINE print_virial_delta
2545 SUBROUTINE build_static_coordinate_virial(virial_xc, features, atom_coord_grad_t, &
2546 grid_coord_grad_t, root_rank, print_components)
2547 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
2550 LOGICAL,
INTENT(IN) :: root_rank
2551 LOGICAL,
INTENT(IN),
OPTIONAL :: print_components
2553 INTEGER :: feature_pos, i, iatom, idir, iw, j, &
2554 jdir, k, local_row, row
2555 LOGICAL :: my_print_components
2556 REAL(kind=
dp) :: tmp
2557 REAL(kind=
dp),
DIMENSION(3) :: atom_grad_sum, grid_grad_sum
2558 REAL(kind=
dp),
DIMENSION(3, 3) :: atom_virial, grid_virial
2559 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad, grid_coord_grad
2561 my_print_components = .false.
2562 IF (
PRESENT(print_components)) my_print_components = print_components
2564 NULLIFY (atom_coord_grad, grid_coord_grad)
2569 grid_virial = 0.0_dp
2570 atom_virial = 0.0_dp
2571 grid_grad_sum = 0.0_dp
2572 atom_grad_sum = 0.0_dp
2574 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2575 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2576 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2577 local_row = local_row + 1
2578 DO feature_pos = features%local_feature_offsets(local_row), &
2579 features%local_feature_offsets(local_row + 1) - 1
2580 row = features%local_feature_rows(feature_pos)
2581 grid_grad_sum(:) = grid_grad_sum(:) + grid_coord_grad(:, row)
2584 tmp = grid_coord_grad(idir, row)*features%grid_coords(jdir, row)
2585 grid_virial(idir, jdir) = grid_virial(idir, jdir) + tmp
2586 virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
2593 cpassert(local_row == features%nflat_local)
2596 DO iatom = 1,
SIZE(features%coarse_0_atomic_coords, 2)
2597 atom_grad_sum(:) = atom_grad_sum(:) + atom_coord_grad(:, iatom)
2600 tmp = atom_coord_grad(idir, iatom)*features%coarse_0_atomic_coords(jdir, iatom)
2601 atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
2602 virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
2608 IF (my_print_components .AND. root_rank)
THEN
2611 CALL print_virial_delta(
"static-grid", grid_virial, .true.)
2612 CALL print_virial_delta(
"static-atom", atom_virial, .true.)
2613 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW| XC coordinate gradient grid sum", &
2615 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW| XC coordinate gradient atom sum", &
2617 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW| XC coordinate gradient total sum", &
2618 grid_grad_sum + atom_grad_sum
2624 END SUBROUTINE build_static_coordinate_virial
2636 SUBROUTINE build_weight_virial(virial_xc, features, exc, grid_weight_grad_t, &
2637 atomic_grid_weight_grad_t, root_rank, print_components)
2638 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
2640 REAL(kind=
dp),
INTENT(IN) :: exc
2642 atomic_grid_weight_grad_t
2643 LOGICAL,
INTENT(IN) :: root_rank
2644 LOGICAL,
INTENT(IN),
OPTIONAL :: print_components
2646 INTEGER :: feature_pos, i, idir, iw, j, k, &
2648 LOGICAL :: my_print_components
2649 REAL(kind=
dp) :: atomic_tmp, exc_tmp, grid_tmp, tmp
2650 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
2652 my_print_components = .false.
2653 IF (
PRESENT(print_components)) my_print_components = print_components
2655 NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
2657 CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
2664 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2665 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2666 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2667 local_row = local_row + 1
2668 DO feature_pos = features%local_feature_offsets(local_row), &
2669 features%local_feature_offsets(local_row + 1) - 1
2670 row = features%local_feature_rows(feature_pos)
2671 grid_tmp = grid_tmp + grid_weight_grad(row)*features%grid_weights(row)
2672 atomic_tmp = atomic_tmp + &
2673 atomic_grid_weight_grad(row)*features%atomic_grid_weights(row)
2678 cpassert(local_row == features%nflat_local)
2680 IF (root_rank) exc_tmp = -exc
2681 tmp = grid_tmp + atomic_tmp + exc_tmp
2683 IF (my_print_components .AND. root_rank)
THEN
2686 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight grid", grid_tmp
2687 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight atomic", atomic_tmp
2688 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight final", exc_tmp
2689 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight residual", tmp
2694 virial_xc(idir, idir) = virial_xc(idir, idir) + tmp
2700 END SUBROUTINE build_weight_virial
2715 density_grad, grad_grad, kin_grad, &
2716 xc_deriv_method_id, global_grid_layout)
2717 TYPE(
pw_r3d_rs_type),
DIMENSION(:),
POINTER :: vxc_rho, vxc_tau, rho_r
2719 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: density_grad
2720 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: grad_grad
2721 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: kin_grad
2722 INTEGER,
INTENT(IN) :: xc_deriv_method_id
2723 LOGICAL,
INTENT(IN),
OPTIONAL :: global_grid_layout
2725 INTEGER :: i, ipt, ispin, j, k, nspins
2726 INTEGER,
DIMENSION(2, 3) :: bo
2727 LOGICAL :: my_global_grid_layout, valid_spin_shape
2728 REAL(kind=
dp) :: dvol_inv
2732 nspins =
SIZE(rho_r)
2733 bo = rho_r(1)%pw_grid%bounds_local
2734 dvol_inv = 1.0_dp/rho_r(1)%pw_grid%dvol
2735 my_global_grid_layout = .false.
2736 IF (
PRESENT(global_grid_layout)) my_global_grid_layout = global_grid_layout
2737 IF (my_global_grid_layout)
THEN
2738 cpassert(
SIZE(density_grad, 1) == product(rho_r(1)%pw_grid%npts))
2740 cpassert(
SIZE(kin_grad, 2) ==
SIZE(density_grad, 2))
2741 cpassert(
SIZE(grad_grad, 3) ==
SIZE(density_grad, 2))
2742 cpassert(
SIZE(grad_grad, 2) == 3)
2743 valid_spin_shape =
SIZE(density_grad, 2) == nspins .OR. &
2744 (nspins == 1 .AND.
SIZE(density_grad, 2) == 2)
2745 cpassert(valid_spin_shape)
2747 ALLOCATE (vxc_rho(nspins), vxc_tau(nspins))
2748 DO ispin = 1, nspins
2749 CALL pw_pool%create_pw(vxc_rho(ispin))
2750 CALL pw_pool%create_pw(vxc_tau(ispin))
2756 CALL pw_pool%create_pw(vxc_g)
2757 IF (.NOT. rho_r(1)%pw_grid%spherical)
CALL pw_pool%create_pw(tmp_g)
2760 DO ispin = 1, nspins
2762 CALL pw_pool%create_pw(grad_pw(i))
2767 DO k = bo(1, 3), bo(2, 3)
2768 DO j = bo(1, 2), bo(2, 2)
2769 DO i = bo(1, 1), bo(2, 1)
2770 IF (my_global_grid_layout)
THEN
2771 ipt = 1 + i - rho_r(1)%pw_grid%bounds(1, 1) + &
2772 rho_r(1)%pw_grid%npts(1)*( &
2773 j - rho_r(1)%pw_grid%bounds(1, 2) + &
2774 rho_r(1)%pw_grid%npts(2)*( &
2775 k - rho_r(1)%pw_grid%bounds(1, 3)))
2779 IF (nspins == 1)
THEN
2780 IF (
SIZE(density_grad, 2) == 1)
THEN
2781 vxc_rho(1)%array(i, j, k) = 0.5_dp*dvol_inv*density_grad(ipt, 1)
2782 vxc_tau(1)%array(i, j, k) = 0.5_dp*dvol_inv*kin_grad(ipt, 1)
2783 grad_pw(1)%array(i, j, k) = 0.5_dp*dvol_inv*grad_grad(ipt, 1, 1)
2784 grad_pw(2)%array(i, j, k) = 0.5_dp*dvol_inv*grad_grad(ipt, 2, 1)
2785 grad_pw(3)%array(i, j, k) = 0.5_dp*dvol_inv*grad_grad(ipt, 3, 1)
2787 vxc_rho(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2788 (density_grad(ipt, 1) + density_grad(ipt, 2))
2789 vxc_tau(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2790 (kin_grad(ipt, 1) + kin_grad(ipt, 2))
2791 grad_pw(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2792 (grad_grad(ipt, 1, 1) + grad_grad(ipt, 1, 2))
2793 grad_pw(2)%array(i, j, k) = 0.5_dp*dvol_inv* &
2794 (grad_grad(ipt, 2, 1) + grad_grad(ipt, 2, 2))
2795 grad_pw(3)%array(i, j, k) = 0.5_dp*dvol_inv* &
2796 (grad_grad(ipt, 3, 1) + grad_grad(ipt, 3, 2))
2799 vxc_rho(ispin)%array(i, j, k) = dvol_inv*density_grad(ipt, ispin)
2800 vxc_tau(ispin)%array(i, j, k) = dvol_inv*kin_grad(ipt, ispin)
2801 grad_pw(1)%array(i, j, k) = dvol_inv*grad_grad(ipt, 1, ispin)
2802 grad_pw(2)%array(i, j, k) = dvol_inv*grad_grad(ipt, 2, ispin)
2803 grad_pw(3)%array(i, j, k) = dvol_inv*grad_grad(ipt, 3, ispin)
2812 CALL xc_pw_divergence(xc_deriv_method_id, grad_pw, tmp_g, vxc_g, vxc_rho(ispin))
2815 CALL pw_pool%give_back_pw(grad_pw(i))
2819 IF (
ASSOCIATED(vxc_g%pw_grid))
CALL pw_pool%give_back_pw(vxc_g)
2820 IF (
ASSOCIATED(tmp_g%pw_grid))
CALL pw_pool%give_back_pw(tmp_g)
2829 SUBROUTINE print_native_grid_diagnostics(features, print_active)
2831 LOGICAL,
INTENT(IN) :: print_active
2833 INTEGER :: atom_rows_max, atom_rows_min, &
2834 chunk_rows_max, chunk_rows_min, iw
2835 REAL(kind=
dp) :: chunk_imbalance
2837 IF (.NOT. print_active)
RETURN
2841 WRITE (unit=iw, fmt=
"(/,T2,A,1X,ES19.11)") &
2842 "SKALA_GPW| Native grid feature electrons", features%electron_count
2843 WRITE (unit=iw, fmt=
"(T2,A,1X,ES19.11)") &
2844 "SKALA_GPW| Native grid feature spin moment", features%spin_moment
2845 WRITE (unit=iw, fmt=
"(T2,A,1X,ES19.11)") &
2846 "SKALA_GPW| Native grid feature kinetic integral", features%kinetic_integral
2847 WRITE (unit=iw, fmt=
"(T2,A,1X,ES19.11)") &
2848 "SKALA_GPW| Native grid feature weight sum", features%grid_weight_sum
2849 IF (
ALLOCATED(features%atomic_grid_sizes))
THEN
2850 atom_rows_min = int(minval(features%atomic_grid_sizes))
2851 atom_rows_max = int(maxval(features%atomic_grid_sizes))
2852 WRITE (unit=iw, fmt=
"(T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,I0)") &
2853 "SKALA_GPW| Native grid atom row range", atom_rows_min,
"to", &
2854 atom_rows_max,
"sum", int(sum(features%atomic_grid_sizes))
2856 IF (features%uses_atom_chunks)
THEN
2857 WRITE (unit=iw, fmt=
"(T2,A,1X,I0,1X,A,1X,I0)") &
2858 "SKALA_GPW| Native grid atom chunk rows", features%chunk_feature_count, &
2859 "of", features%nflat
2860 IF (
ALLOCATED(features%chunk_grad_counts))
THEN
2861 chunk_rows_min = minval(features%chunk_grad_counts)/ngrad_per_point
2862 chunk_rows_max = maxval(features%chunk_grad_counts)/ngrad_per_point
2863 chunk_imbalance = real(chunk_rows_max, kind=
dp)/real(max(1, chunk_rows_min), kind=
dp)
2864 WRITE (unit=iw, fmt=
"(T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,ES12.5)") &
2865 "SKALA_GPW| Native grid atom chunk row range", chunk_rows_min, &
2866 "to", chunk_rows_max,
"imbalance", chunk_imbalance
2870 END SUBROUTINE print_native_grid_diagnostics
2879 FUNCTION configure_native_grid_cuda(use_cuda, requested_device, group)
RESULT(selected_device)
2880 LOGICAL,
INTENT(IN) :: use_cuda
2881 INTEGER,
INTENT(IN) :: requested_device
2885 INTEGER :: cuda_device_count, iw, pe, selected_device
2886 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: selected_devices
2888 selected_device = -1
2890 IF (.NOT. use_cuda)
RETURN
2893 cuda_device_count = 0
2897 IF (cuda_device_count > 0)
THEN
2898 IF (requested_device < 0)
THEN
2899 selected_device = mod(group%mepos, cuda_device_count)
2901 selected_device = requested_device
2904 IF (selected_device >= cuda_device_count)
THEN
2905 CALL cp_abort(__location__, &
2906 "GAUXC%NATIVE_GRID_CUDA_DEVICE selects a CUDA device outside the visible "// &
2907 "Torch CUDA device range.")
2911 ALLOCATE (selected_devices(group%num_pe))
2912 CALL group%allgather(selected_device, selected_devices)
2914 IF (group%mepos /= 0)
THEN
2915 DEALLOCATE (selected_devices)
2918 IF (selected_device == logged_cuda_device .AND. &
2919 cuda_device_count == logged_cuda_device_count .AND. &
2920 group%num_pe == logged_cuda_nproc .AND. &
2921 requested_device == logged_cuda_request)
THEN
2922 DEALLOCATE (selected_devices)
2928 DEALLOCATE (selected_devices)
2931 IF (selected_device >= 0)
THEN
2932 WRITE (unit=iw, fmt=
"(/,T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,I0)") &
2933 "SKALA_GPW| Native grid Torch CUDA device", selected_device, &
2934 "of", cuda_device_count,
"requested", requested_device
2936 WRITE (unit=iw, fmt=
"(/,T2,A)") &
2937 "SKALA_GPW| Native grid Torch CUDA requested, but no Torch CUDA device is visible"
2939 WRITE (unit=iw, fmt=
"(T2,A)", advance=
"NO") &
2940 "SKALA_GPW| Native grid Torch CUDA rank devices"
2941 DO pe = 1, group%num_pe
2942 WRITE (unit=iw, fmt=
"(1X,I0,A,I0)", advance=
"NO") pe - 1,
":", selected_devices(pe)
2944 WRITE (unit=iw, fmt=*)
2946 logged_cuda_device = selected_device
2947 logged_cuda_device_count = cuda_device_count
2948 logged_cuda_nproc = group%num_pe
2949 logged_cuda_request = requested_device
2950 DEALLOCATE (selected_devices)
2952 END FUNCTION configure_native_grid_cuda
2960 SUBROUTINE ensure_model_loaded(model_path, cuda_device, xc_section)
2961 CHARACTER(len=*),
INTENT(IN) :: model_path
2962 INTEGER,
INTENT(IN) :: cuda_device
2971 IF (cached_model_loaded)
THEN
2972 IF (trim(cached_model_path) == trim(model_path) .AND. &
2973 cached_model_cuda_device == cuda_device .AND. &
2974 (cached_model_fp64 .EQV. fp64))
RETURN
2976 cached_model_loaded = .false.
2980 cached_model_path = model_path
2981 cached_model_cuda_device = cuda_device
2982 cached_model_fp64 = fp64
2983 cached_model_loaded = .true.
2985 END SUBROUTINE ensure_model_loaded
2992 SUBROUTINE get_skala_model_path(xc_section, model_path)
2994 CHARACTER(len=default_path_length),
INTENT(OUT) :: model_path
2996 CHARACTER(len=default_path_length) :: model_key
2997 INTEGER :: env_status
2998 LOGICAL :: native_grid_use_cuda
3002 IF (.NOT.
ASSOCIATED(gauxc_section))
THEN
3003 cpabort(
"Native SKALA GPW requires an XC_FUNCTIONAL%GAUXC section")
3007 model_key = adjustl(model_path)
3009 IF (trim(model_key) ==
"NONE" .OR. trim(model_key) ==
"")
THEN
3010 cpabort(
"Native SKALA GPW requires GAUXC%MODEL SKALA or a TorchScript model path")
3011 ELSE IF (trim(model_key) ==
"SKALA")
THEN
3013 IF (native_grid_use_cuda)
THEN
3014 CALL get_environment_variable(
"GAUXC_SKALA_CUDA_MODEL", model_path, status=env_status)
3015 IF (env_status == 0 .AND. len_trim(model_path) > 0)
RETURN
3017 CALL get_environment_variable(
"SKALA_MODEL", model_path, status=env_status)
3018 IF (env_status /= 0 .OR. len_trim(model_path) == 0)
THEN
3019 IF (native_grid_use_cuda)
THEN
3020 CALL cp_abort(__location__, &
3021 "MODEL SKALA CUDA path requires GAUXC_SKALA_CUDA_MODEL or SKALA_MODEL")
3023 CALL cp_abort(__location__, &
3024 "MODEL SKALA requires the SKALA_MODEL environment variable")
3029 END SUBROUTINE get_skala_model_path
3043 NULLIFY (gauxc_section)
3044 IF (.NOT.
ASSOCIATED(xc_section))
RETURN
3047 IF (.NOT.
ASSOCIATED(functionals))
RETURN
3053 IF (.NOT.
ASSOCIATED(xc_fun))
EXIT
3054 IF (xc_fun%section%name ==
"GAUXC")
THEN
3055 gauxc_section => xc_fun
Handles all functions related to the CELL.
various utilities that regard array of different kinds: output, allocation,... maybe it is not a good...
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
integer, parameter, public default_path_length
Interface to the message passing library MPI.
Fortran API for the offload package, which is written in C.
subroutine, public offload_set_chosen_device(device_id)
Selects the chosen device to be used.
Define the data structure for the particle information.
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
Build SKALA TorchScript feature dictionaries from CP2K GPW real-space grids.
subroutine, public skala_gpw_atom_subchunk_layout(max_rows, atom_begin, atom_count, row_begin, row_count)
Build atom and row bounds for all atom-contiguous subchunks in one pass.
integer, parameter, public skala_gpw_atom_partition_hard
pure real(kind=dp) function, public smooth_partition_atomic_weight_scale_derivative(weight)
Derivative of the sparse atom-row quadrature taper with respect to partition weight.
subroutine, public skala_gpw_feature_release(features)
Release Torch objects and backing arrays owned by a feature bundle.
integer function, public skala_gpw_atom_subchunk_count(max_rows)
Return how many atom-contiguous subchunks the cached rank chunk needs.
subroutine, public skala_gpw_feature_build(features, rho_set, rho_r, particle_set, cell, requires_grad, weights, requires_coordinate_grad, requires_stress_grad, use_atom_chunks, route_atom_chunks, atom_partition)
Build a flat SKALA molecular feature dictionary from a local GPW grid.
subroutine, public skala_gpw_feature_build_atom_subchunk_bounds(parent, features, atom_begin, atom_count, row_begin, row_count, requires_grad)
Build an atom-contiguous subchunk feature bundle from precomputed bounds.
subroutine, public skala_gpw_smooth_partition_derivatives(grid_point, atom_coords, cell, weights, included, dweights_datom, dweights_dstrain)
Build smooth atom weights and their atom/cell deformation derivatives.
integer, parameter, public skala_gpw_atom_partition_smooth
Experimental CP2K-native GPW real-space-grid path for SKALA TorchScript models.
integer, parameter, public skala_gapw_density_partition_soft_only
subroutine, public skala_gpw_weight_derivative(weight_deriv_r, rho_r, rho_g, tau, xc_section, weights, pw_pool, particle_set, cell)
Evaluate the derivative of native SKALA XC energy with respect to CP2K's external real-space integrat...
subroutine, public skala_gapw_atom_composite_energy(xc_section, group, density, grad, kin, grid_coords, grid_weights, atomic_grid_weights, atomic_grid_sizes, atomic_coords, exc, density_grad_out, grad_grad_out, kin_grad_out, grid_coord_grad_out, grid_weight_grad_out, atomic_grid_weight_grad_out, atom_coord_grad_out)
Evaluate a rank-local set of complete atom blocks and sum their SKALA energies.
subroutine, public ensure_native_skala_grid_scope(xc_section)
Enforce the currently implemented native SKALA GPW input scope.
subroutine, public skala_gpw_eval(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, weights, pw_pool, particle_set, cell, compute_virial, virial_xc, just_energy, atom_force)
Evaluate SKALA energy and first derivatives on a CP2K GPW grid.
subroutine, public build_vxc_from_feature_grads(vxc_rho, vxc_tau, rho_r, pw_pool, density_grad, grad_grad, kin_grad, xc_deriv_method_id, global_grid_layout)
Fill CP2K VXC real-space arrays from Torch feature gradients.
integer, parameter, public skala_gapw_density_partition_none
logical function, public native_skala_gapw_composite_direct_ao(xc_section)
Return true if the GAPW composite reference uses direct full-ORB collocation.
logical function, public xc_section_uses_gauxc_model(xc_section)
Return true if the GAUXC subsection requests a model evaluation.
logical function, public native_skala_uses_atom_composite_grid(xc_section)
Return true when native Skala uses atom-centered grids.
logical function, public xc_section_uses_native_skala_evaluator(xc_section)
Return true when SKALA must be evaluated by the CP2K-native grid machinery.
integer, parameter, public skala_gapw_density_partition_hard_minus_soft
integer function, public skala_gapw_representation(xc_section)
Return the pseudopotential GAPW representation selected for an active model.
integer function, public native_skala_gapw_density_partition(xc_section)
Return the hard/soft GAPW one-center density partition for native SKALA.
type(section_vals_type) function, pointer, public get_gauxc_section(xc_section)
Return the first GAUXC functional subsection, if present.
subroutine, public skala_gapw_atom_vxc_of_r(xc_section, grid_atom, group, atom_coord, rho, drho, tau, weights, lsd, nspins, na, nr, exc, vxc, vxg, vtau, energy_only, atom_force, atom_virial)
Evaluate SKALA on a GAPW one-center atomic grid.
logical function, public native_skala_gapw_atom_composite_requested(xc_section)
Return true when the explicit atom-centered composite reference is requested.
type(skala_torch_model_type), save cached_model
logical function, public native_skala_gapw_composite_reference(xc_section)
Return true if native SKALA should use the full GAPW ORB density on one common grid.
logical function, public xc_section_uses_native_skala_grid(xc_section)
Return true if the GAUXC subsection requests the CP2K-native GPW grid path.
integer, parameter, public skala_gapw_density_partition_hard_only
Small CP2K wrapper around the SKALA TorchScript functional protocol.
subroutine, public skala_torch_model_release(model)
Release a loaded SKALA TorchScript model.
subroutine, public skala_torch_model_load(model, filename, fp64)
Load a SKALA TorchScript model and its feature metadata.
subroutine, public skala_torch_model_get_exc(model, inputs, grid_weights, exc_tensor, exc)
Evaluate the weighted SKALA exchange-correlation energy.
Utilities for string manipulations.
elemental subroutine, public uppercase(string)
Convert all lower case characters in a string to upper case.
subroutine, public torch_dict_release(dict)
Releases a Torch dictionary and all its ressources.
subroutine, public torch_use_cuda(use_cuda)
Select whether Torch wrappers should use CUDA when available.
subroutine, public torch_tensor_backward_scalar(tensor)
Runs autograd on a scalar Torch tensor.
subroutine, public torch_tensor_narrow(tensor, dim, start_index, length, result)
Creates a view of a contiguous tensor slice.
subroutine, public torch_tensor_to_device_leaf(tensor, requires_grad)
Moves a tensor to the active Torch device and makes it an autograd leaf.
subroutine, public torch_dict_create(dict)
Creates an empty Torch dictionary.
subroutine, public torch_tensor_grad(tensor, grad)
Returns the gradient of a Torch tensor which was computed by autograd.
subroutine, public torch_tensor_grad_batch3(tensor1, tensor2, tensor3, grad1, grad2, grad3)
Copies three autograd gradients to CPU memory.
integer function, public torch_cuda_device_count()
Return the number of CUDA devices visible to Torch.
subroutine, public torch_dict_insert(dict, key, tensor)
Inserts a Torch tensor into a Torch dictionary.
logical function, public torch_cuda_is_available()
Returns true iff the Torch CUDA backend is available.
subroutine, public torch_tensor_release(tensor)
Releases a Torch tensor and all its ressources.
subroutine, public xc_rho_set_create(rho_set, local_bounds, rho_cutoff, drho_cutoff, tau_cutoff)
allocates and does (minimal) initialization of a rho_set
subroutine, public xc_rho_set_release(rho_set, pw_pool)
releases the given rho_set
subroutine, public xc_rho_set_update(rho_set, rho_r, rho_g, tau, needs, xc_deriv_method_id, xc_rho_smooth_id, pw_pool, spinflip)
updates the given rho set with the density given by rho_r (and rho_g). The rho set will contain the c...
subroutine, public xc_rho_set_get(rho_set, can_return_null, rho, drho, norm_drho, rhoa, rhob, norm_drhoa, norm_drhob, rho_1_3, rhoa_1_3, rhob_1_3, laplace_rho, laplace_rhoa, laplace_rhob, drhoa, drhob, rho_cutoff, drho_cutoff, tau_cutoff, tau, tau_a, tau_b, local_bounds)
returns the various attributes of rho_set
contains utility functions for the xc package
subroutine, public xc_pw_divergence(xc_deriv_method_id, pw_to_deriv, tmp_g, vxc_g, vxc_r)
Calculates the divergence of pw_to_deriv.
elemental logical function, public xc_requires_tmp_g(xc_deriv_id)
...
Type defining parameters related to the simulation cell.
represent a pointer to a contiguous 3d array
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
contains a flag for each component of xc_rho_set, so that you can use it to tell which components you...
represent a density, with all the representation and data needed to perform a functional evaluation