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 INTEGER,
SAVE :: cached_model_cuda_device = -3
103 INTEGER,
SAVE :: logged_cuda_device = -3, &
104 logged_cuda_device_count = -1, &
105 logged_cuda_nproc = -1, &
106 logged_cuda_request = -3
117 LOGICAL :: uses_native_grid
121 uses_native_grid = .false.
123 IF (
ASSOCIATED(gauxc_section))
THEN
136 INTEGER :: representation
144 cpassert(
ASSOCIATED(gauxc_section))
146 i_val=representation)
148 SELECT CASE (representation)
153 CALL cp_abort(__location__,
"Unknown pseudopotential GAPW representation.")
165 LOGICAL :: uses_native_evaluator
180 LOGICAL :: use_composite_reference
182 LOGICAL :: native_grid
185 use_composite_reference = .false.
186 native_grid = .false.
188 IF (
ASSOCIATED(gauxc_section))
THEN
191 l_val=use_composite_reference)
193 use_composite_reference = native_grid .AND. use_composite_reference
204 LOGICAL :: use_atom_composite
206 LOGICAL :: native_grid
209 use_atom_composite = .false.
210 native_grid = .false.
212 IF (
ASSOCIATED(gauxc_section))
THEN
215 "NATIVE_GRID_GAPW_ATOM_COMPOSITE_REFERENCE", &
216 l_val=use_atom_composite)
218 use_atom_composite = native_grid .AND. use_atom_composite
229 LOGICAL :: use_atom_composite
231 INTEGER :: composite_grid
234 use_atom_composite = .false.
237 IF (
ASSOCIATED(gauxc_section))
THEN
239 i_val=composite_grid)
241 SELECT CASE (composite_grid)
245 use_atom_composite = .true.
247 CALL cp_abort(__location__,
"Unknown native-grid layout.")
259 LOGICAL :: use_direct_ao
263 use_direct_ao = .false.
265 IF (
ASSOCIATED(gauxc_section))
THEN
280 LOGICAL :: uses_gauxc_model
282 CHARACTER(len=default_path_length) :: model_key, model_name, xc_key, xc_name
285 uses_gauxc_model = .false.
287 IF (
ASSOCIATED(gauxc_section))
THEN
290 model_key = adjustl(model_name)
291 xc_key = adjustl(xc_name)
294 uses_gauxc_model = (trim(model_key) /=
"" .AND. trim(model_key) /=
"NONE" .AND. &
295 trim(model_key) /= trim(xc_key))
313 IF (
ASSOCIATED(gauxc_section))
THEN
318 SELECT CASE (partition)
325 CALL cp_abort(__location__, &
326 "Unknown GAUXC%NATIVE_GRID_GAPW_DENSITY_PARTITION value.")
338 CHARACTER(len=default_path_length) :: model_key, model_name
339 INTEGER :: ifun, nfun
340 LOGICAL :: native_grid
343 NULLIFY (gauxc_section)
344 IF (.NOT.
ASSOCIATED(xc_section))
THEN
345 cpabort(
"Native SKALA GPW requires an XC section")
349 IF (.NOT.
ASSOCIATED(functionals))
THEN
350 cpabort(
"Native SKALA GPW requires an XC_FUNCTIONAL section")
358 IF (.NOT.
ASSOCIATED(xc_fun))
EXIT
360 IF (xc_fun%section%name ==
"GAUXC") gauxc_section => xc_fun
363 IF (.NOT.
ASSOCIATED(gauxc_section))
THEN
364 cpabort(
"Native SKALA GPW requires an XC_FUNCTIONAL%GAUXC section")
367 cpabort(
"Native SKALA GPW requires GAUXC to be the only XC functional")
371 IF (.NOT. native_grid .AND. &
375 model_key = adjustl(model_name)
377 IF (trim(model_key) ==
"NONE" .OR. trim(model_key) ==
"")
THEN
378 cpabort(
"Native SKALA GPW requires GAUXC%MODEL SKALA or a TorchScript model path")
401 SUBROUTINE skala_gpw_eval(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, &
402 weights, pw_pool, particle_set, cell, compute_virial, virial_xc, &
403 just_energy, atom_force)
405 REAL(kind=
dp),
INTENT(OUT) :: exc
414 LOGICAL,
INTENT(IN) :: compute_virial
415 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(OUT) :: virial_xc
416 LOGICAL,
INTENT(IN),
OPTIONAL :: just_energy
417 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT), &
418 OPTIONAL :: atom_force
420 CHARACTER(len=default_path_length) :: model_path
421 INTEGER :: i, ipt, ispin, iw, j, k, native_grid_atom_chunk_max_rows, &
422 native_grid_atom_partition, native_grid_atom_subchunks, native_grid_cuda_device, nspins, &
423 omp_max_threads_restore, phase_handle, selected_cuda_device, xc_deriv_method_id, &
425 INTEGER,
DIMENSION(2, 3) :: bo
426 LOGICAL :: has_atom_chunk_work, have_atom_coord_grad, lsd, my_just_energy, &
427 native_grid_atom_chunk_routing, native_grid_atom_chunks, native_grid_diagnostics, &
428 native_grid_use_cuda, needs_atom_force, use_atom_subchunks
429 REAL(kind=
dp) :: density_contraction, tau_contraction
430 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: density_grad, kin_grad
431 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: grad_grad
432 REAL(kind=
dp),
DIMENSION(3, 3) :: virial_before
436 atomic_grid_weight_grad_t, exc_tensor, &
437 grid_coord_grad_t, grid_weight_grad_t
443 my_just_energy = .false.
444 IF (
PRESENT(just_energy)) my_just_energy = just_energy
445 needs_atom_force =
PRESENT(atom_force)
446 IF (needs_atom_force) atom_force = 0.0_dp
447 have_atom_coord_grad = .false.
448 omp_max_threads_restore = omp_get_max_threads()
450 IF (compute_virial .AND. my_just_energy)
THEN
451 CALL cp_abort(__location__, &
452 "Native SKALA GPW stress/virial requires feature gradients.")
454 IF (.NOT.
ASSOCIATED(rho_g))
THEN
455 CALL cp_abort(__location__, &
456 "Native SKALA GPW requires the reciprocal-space density to form density gradients.")
458 IF (.NOT.
ASSOCIATED(tau))
THEN
459 CALL cp_abort(__location__, &
460 "Native SKALA GPW requires the kinetic-energy density.")
465 CALL get_skala_model_path(xc_section, model_path)
469 i_val=native_grid_cuda_device)
471 l_val=native_grid_atom_chunks)
473 l_val=native_grid_atom_chunk_routing)
475 i_val=native_grid_atom_chunk_max_rows)
477 i_val=native_grid_atom_partition)
478 SELECT CASE (native_grid_atom_partition)
484 CALL cp_abort(__location__, &
485 "Unknown GAUXC%NATIVE_GRID_ATOM_PARTITION value.")
487 native_grid_atom_chunk_routing = native_grid_atom_chunk_routing .OR. native_grid_atom_chunks
488 native_grid_atom_chunks = native_grid_atom_chunks .OR. native_grid_atom_chunk_routing
489 IF (native_grid_atom_chunk_max_rows < -1)
THEN
490 CALL cp_abort(__location__, &
491 "GAUXC%NATIVE_GRID_ATOM_CHUNK_MAX_ROWS must be -1, zero, or positive.")
493 IF (needs_atom_force .OR. compute_virial)
THEN
497 native_grid_atom_chunk_routing = .false.
498 native_grid_atom_chunks = .false.
502 selected_cuda_device = configure_native_grid_cuda( &
503 native_grid_use_cuda, native_grid_cuda_device, rho_r(1)%pw_grid%para%group)
504 CALL ensure_model_loaded(model_path, selected_cuda_device)
507 needs%rho_spin = .true.
508 needs%drho_spin = .true.
509 needs%tau_spin = .true.
520 rho_r(1)%pw_grid%bounds_local, &
525 xc_deriv_method_id, xc_rho_smooth_id, pw_pool)
528 requires_grad=(.NOT. my_just_energy), weights=weights, &
529 requires_coordinate_grad=(needs_atom_force .OR. compute_virial), &
530 requires_stress_grad=compute_virial, &
531 use_atom_chunks=native_grid_atom_chunks, &
532 route_atom_chunks=native_grid_atom_chunk_routing, &
533 atom_partition=native_grid_atom_partition)
534 CALL section_vals_val_get(gauxc_section,
"NATIVE_GRID_DIAGNOSTICS", l_val=native_grid_diagnostics)
535 IF (native_grid_diagnostics)
THEN
536 CALL print_native_grid_diagnostics(features, rho_r(1)%pw_grid%para%group%mepos == 0)
539 IF (features%uses_atom_chunks .AND. native_grid_atom_chunk_max_rows == -1)
THEN
540 native_grid_atom_chunk_max_rows = auto_atom_chunk_max_rows(features, &
541 rho_r(1)%pw_grid%para%group)
543 IF (native_grid_diagnostics .AND. features%uses_atom_chunks .AND. &
544 rho_r(1)%pw_grid%para%group%mepos == 0)
THEN
547 WRITE (unit=iw, fmt=
"(T2,A,1X,I0)") &
548 "SKALA_GPW| Native grid atom chunk max rows", native_grid_atom_chunk_max_rows
551 native_grid_atom_subchunks = 1
552 IF (features%uses_atom_chunks .AND. native_grid_atom_chunk_max_rows > 0)
THEN
554 CALL rho_r(1)%pw_grid%para%group%max(native_grid_atom_subchunks)
556 use_atom_subchunks = features%uses_atom_chunks .AND. native_grid_atom_subchunks > 1
557 has_atom_chunk_work = .NOT. features%uses_atom_chunks .OR. features%chunk_feature_count > 0
559 IF (use_atom_subchunks)
THEN
560 CALL evaluate_atom_subchunks(features, rho_r(1)%pw_grid%para%group, &
561 native_grid_atom_chunk_max_rows, &
562 compute_grads=(.NOT. my_just_energy), exc=exc, &
563 density_grad=density_grad, grad_grad=grad_grad, &
564 kin_grad=kin_grad, collapse_spin_grads=(nspins == 1))
565 ELSE IF (has_atom_chunk_work)
THEN
567 features%grid_weights_t, exc_tensor, exc)
569 IF (features%uses_atom_chunks)
CALL rho_r(1)%pw_grid%para%group%sum(exc)
571 IF (.NOT. my_just_energy)
THEN
572 IF (.NOT. use_atom_subchunks)
THEN
573 IF (has_atom_chunk_work)
THEN
574 CALL timeset(
"skala_gpw_backward", phase_handle)
576 CALL timestop(phase_handle)
578 IF (compute_virial)
THEN
579 IF (native_grid_diagnostics) virial_before = virial_xc
580 CALL build_weight_virial(virial_xc, features, exc, grid_weight_grad_t, &
581 atomic_grid_weight_grad_t, &
582 rho_r(1)%pw_grid%para%group%mepos == 0, &
583 native_grid_diagnostics)
584 IF (native_grid_diagnostics)
THEN
585 CALL print_virial_delta(
"weight-residual", virial_xc - virial_before, &
586 rho_r(1)%pw_grid%para%group%mepos == 0)
591 CALL timeset(
"skala_gpw_grad_fetch", phase_handle)
592 IF (features%uses_atom_chunks)
THEN
593 CALL fetch_and_gather_atom_chunk_grads(features, rho_r(1)%pw_grid%para%group, &
594 density_grad, grad_grad, kin_grad)
596 CALL fetch_local_feature_grads(features, density_grad, grad_grad, kin_grad)
598 CALL timestop(phase_handle)
600 IF (needs_atom_force)
THEN
601 CALL add_explicit_coordinate_force(atom_force, features, atom_coord_grad_t, &
602 rho_r(1)%pw_grid%para%group%mepos == 0)
604 CALL add_smooth_partition_force(atom_force, features, particle_set, cell, rho_r, &
605 grid_weight_grad_t, atomic_grid_weight_grad_t)
607 have_atom_coord_grad = .true.
610 CALL timeset(
"skala_gpw_vxc_unpack", phase_handle)
611 IF (native_grid_diagnostics)
THEN
612 bo = rho_r(1)%pw_grid%bounds_local
613 density_contraction = 0.0_dp
614 tau_contraction = 0.0_dp
616 DO k = bo(1, 3), bo(2, 3)
617 DO j = bo(1, 2), bo(2, 2)
618 DO i = bo(1, 1), bo(2, 1)
620 IF (nspins == 1)
THEN
621 density_contraction = density_contraction + rho_r(1)%array(i, j, k)* &
622 0.5_dp*(density_grad(ipt, 1) + density_grad(ipt, 2))
623 tau_contraction = tau_contraction + tau(1)%array(i, j, k)* &
624 0.5_dp*(kin_grad(ipt, 1) + kin_grad(ipt, 2))
627 density_contraction = density_contraction + &
628 rho_r(ispin)%array(i, j, k)*density_grad(ipt, ispin)
629 tau_contraction = tau_contraction + &
630 tau(ispin)%array(i, j, k)*kin_grad(ipt, ispin)
636 CALL rho_r(1)%pw_grid%para%group%sum(density_contraction)
637 CALL rho_r(1)%pw_grid%para%group%sum(tau_contraction)
638 IF (rho_r(1)%pw_grid%para%group%mepos == 0)
THEN
641 WRITE (iw,
"(T2,A,1X,ES20.10)") &
642 "SKALA_GPW| XC density-gradient contraction", density_contraction
643 WRITE (iw,
"(T2,A,1X,ES20.10)") &
644 "SKALA_GPW| XC kinetic-gradient contraction", tau_contraction
648 IF (compute_virial)
THEN
649 IF (native_grid_diagnostics) virial_before = virial_xc
650 CALL build_virial_from_feature_grads(virial_xc, rho_set, rho_r, grad_grad)
651 IF (native_grid_diagnostics)
THEN
652 CALL print_virial_delta(
"feature-gradient", virial_xc - virial_before, &
653 rho_r(1)%pw_grid%para%group%mepos == 0)
654 virial_before = virial_xc
656 IF (.NOT. have_atom_coord_grad)
THEN
658 have_atom_coord_grad = .true.
660 CALL build_static_coordinate_virial(virial_xc, features, atom_coord_grad_t, &
662 rho_r(1)%pw_grid%para%group%mepos == 0, &
663 native_grid_diagnostics)
664 IF (native_grid_diagnostics)
THEN
665 CALL print_virial_delta(
"static-coordinates", virial_xc - virial_before, &
666 rho_r(1)%pw_grid%para%group%mepos == 0)
667 virial_before = virial_xc
670 CALL build_smooth_partition_virial(virial_xc, features, particle_set, cell, rho_r, &
671 grid_weight_grad_t, atomic_grid_weight_grad_t)
672 IF (native_grid_diagnostics)
THEN
673 CALL print_virial_delta(
"smooth-partition", virial_xc - virial_before, &
674 rho_r(1)%pw_grid%para%group%mepos == 0)
675 virial_before = virial_xc
679 CALL omp_set_num_threads(omp_max_threads_restore)
681 density_grad, grad_grad, kin_grad, &
683 CALL timestop(phase_handle)
685 CALL timeset(
"skala_gpw_grad_release", phase_handle)
686 DEALLOCATE (density_grad, grad_grad, kin_grad)
688 CALL timestop(phase_handle)
691 CALL timeset(
"skala_gpw_cleanup", phase_handle)
696 CALL omp_set_num_threads(omp_max_threads_restore)
697 CALL timestop(phase_handle)
715 weights, pw_pool, particle_set, cell)
726 CHARACTER(len=default_path_length) :: model_path
727 INTEGER :: feature_begin, feature_end, feature_pos, i, iatom, j, k, local_row, &
728 native_grid_atom_partition, native_grid_cuda_device, natom, nspins, &
729 omp_max_threads_restore, row, selected_cuda_device, xc_deriv_method_id, xc_rho_smooth_id
730 INTEGER,
DIMENSION(2, 3) :: bo
731 LOGICAL :: lsd, native_grid_use_cuda
732 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: included
733 REAL(kind=
dp) :: exc, local_derivative
734 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: partition_weights
735 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: atom_coords_pbc
736 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
737 REAL(kind=
dp),
DIMENSION(3) :: grid_point
738 REAL(kind=
dp),
DIMENSION(:),
POINTER :: grid_weight_grad
745 cpassert(
ASSOCIATED(rho_r))
746 cpassert(
ASSOCIATED(rho_g))
747 cpassert(
ASSOCIATED(tau))
749 omp_max_threads_restore = omp_get_max_threads()
753 CALL get_skala_model_path(xc_section, model_path)
757 i_val=native_grid_cuda_device)
759 i_val=native_grid_atom_partition)
760 SELECT CASE (native_grid_atom_partition)
766 CALL cp_abort(__location__, &
767 "Unknown GAUXC%NATIVE_GRID_ATOM_PARTITION value.")
774 selected_cuda_device = configure_native_grid_cuda( &
775 native_grid_use_cuda, native_grid_cuda_device, rho_r(1)%pw_grid%para%group)
776 CALL ensure_model_loaded(model_path, selected_cuda_device)
779 needs%rho_spin = .true.
780 needs%drho_spin = .true.
781 needs%tau_spin = .true.
792 rho_r(1)%pw_grid%bounds_local, &
797 xc_deriv_method_id, xc_rho_smooth_id, pw_pool)
800 requires_grad=.false., weights=weights, &
801 requires_coordinate_grad=.false., &
802 requires_stress_grad=.true., &
803 use_atom_chunks=.false., route_atom_chunks=.false., &
804 atom_partition=native_grid_atom_partition)
808 NULLIFY (grid_weight_grad)
812 natom =
SIZE(particle_set)
814 ALLOCATE (atom_coords_pbc(3, natom), included(natom), partition_weights(natom), &
815 dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
817 atom_coords_pbc(:, iatom) =
pbc(particle_set(iatom)%r, cell, positive_range=.true.)
821 bo = rho_r(1)%pw_grid%bounds_local
823 DO k = bo(1, 3), bo(2, 3)
824 DO j = bo(1, 2), bo(2, 2)
825 DO i = bo(1, 1), bo(2, 1)
826 local_row = local_row + 1
827 feature_begin = features%local_feature_offsets(local_row)
828 feature_end = features%local_feature_offsets(local_row + 1) - 1
829 local_derivative = 0.0_dp
831 cpassert(feature_end == feature_begin)
832 row = features%local_feature_rows(feature_begin)
833 local_derivative = grid_weight_grad(row)
835 grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
837 grid_point, atom_coords_pbc, cell, partition_weights, included, &
838 dweights_datom, dweights_dstrain)
839 cpassert(feature_end - feature_begin + 1 == count(included))
840 feature_pos = feature_begin
842 IF (.NOT. included(iatom)) cycle
843 row = features%local_feature_rows(feature_pos)
844 local_derivative = local_derivative + &
845 partition_weights(iatom)*grid_weight_grad(row)
846 feature_pos = feature_pos + 1
848 cpassert(feature_pos == feature_end + 1)
850 weight_deriv_r%array(i, j, k) = local_derivative
854 cpassert(local_row == features%nflat_local)
856 IF (
ALLOCATED(atom_coords_pbc))
THEN
857 DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, &
865 CALL omp_set_num_threads(omp_max_threads_restore)
892 rho, drho, tau, weights, lsd, nspins, na, nr, &
893 exc, vxc, vxg, vtau, energy_only, atom_force, atom_virial)
898 REAL(kind=
dp),
DIMENSION(3),
INTENT(IN) :: atom_coord
899 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: rho, tau, vxc, vtau
900 REAL(kind=
dp),
DIMENSION(:, :, :, :),
POINTER :: drho, vxg
901 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: weights
902 LOGICAL,
INTENT(IN) :: lsd
903 INTEGER,
INTENT(IN) :: nspins, na, nr
904 REAL(kind=
dp),
INTENT(OUT) :: exc
905 LOGICAL,
INTENT(IN),
OPTIONAL :: energy_only
906 REAL(kind=
dp),
DIMENSION(3),
INTENT(OUT), &
907 OPTIONAL :: atom_force
908 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(OUT), &
909 OPTIONAL :: atom_virial
911 CHARACTER(len=default_path_length) :: model_path
912 INTEGER :: ia, idir, ir, native_grid_cuda_device, &
913 jdir, nflat, omp_max_threads_restore, row, &
915 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:) :: atomic_grid_sizes
916 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:, :) :: atomic_grid_size_bound_shape
917 LOGICAL :: need_coord_grad, my_energy_only, native_grid_use_cuda
919 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: atomic_grid_weights, grid_weights
920 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: coarse_0_atomic_coords, density, &
922 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: grad
923 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad, density_grad, &
924 grid_coord_grad, kin_grad
925 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad
929 atomic_grid_sizes_t, &
930 atomic_grid_weights_t, &
932 coarse_0_atomic_coords_t, density_t, &
933 density_grad_t, exc_tensor, grad_t, &
934 grad_grad_t, grid_coord_grad_t, &
935 grid_coords_t, grid_weights_t, kin_t, &
938 cpassert(
ASSOCIATED(xc_section))
939 cpassert(
ASSOCIATED(grid_atom))
940 cpassert(
ASSOCIATED(rho))
941 cpassert(
ASSOCIATED(drho))
942 cpassert(
ASSOCIATED(tau))
943 omp_max_threads_restore = omp_get_max_threads()
945 my_energy_only = .false.
946 IF (
PRESENT(energy_only)) my_energy_only = energy_only
947 need_coord_grad =
PRESENT(atom_force) .OR.
PRESENT(atom_virial)
949 IF (
PRESENT(atom_force)) atom_force = 0.0_dp
950 IF (
PRESENT(atom_virial)) atom_virial = 0.0_dp
951 IF (.NOT. my_energy_only)
THEN
957 CALL get_skala_model_path(xc_section, model_path)
959 cpassert(
ASSOCIATED(gauxc_section))
962 i_val=native_grid_cuda_device)
964 selected_cuda_device = configure_native_grid_cuda( &
965 native_grid_use_cuda, native_grid_cuda_device, group)
966 CALL ensure_model_loaded(model_path, selected_cuda_device)
969 ALLOCATE (density(nflat, 2), grad(nflat, 3, 2), kin(nflat, 2), &
970 grid_coords(3, nflat), grid_weights(nflat), &
971 atomic_grid_weights(nflat), atomic_grid_sizes(1), &
972 coarse_0_atomic_coords(3, 1), atomic_grid_size_bound_shape(0, nflat))
977 grid_weights = 0.0_dp
978 atomic_grid_weights = 0.0_dp
979 atomic_grid_sizes(1) = int(nflat, kind=
int_8)
980 atomic_grid_size_bound_shape = 0_int_8
981 coarse_0_atomic_coords(:, 1) = atom_coord
987 grid_coords(1, row) = atom_coord(1) + grid_atom%rad(ir)* &
988 grid_atom%sin_pol(ia)*grid_atom%cos_azi(ia)
989 grid_coords(2, row) = atom_coord(2) + grid_atom%rad(ir)* &
990 grid_atom%sin_pol(ia)*grid_atom%sin_azi(ia)
991 grid_coords(3, row) = atom_coord(3) + grid_atom%rad(ir)*grid_atom%cos_pol(ia)
992 grid_weights(row) = weights(ia, ir)
993 atomic_grid_weights(row) = weights(ia, ir)
994 IF (nspins == 1)
THEN
995 density(row, :) = 0.5_dp*rho(ia, ir, 1)
997 grad(row, idir, :) = 0.5_dp*drho(idir, ia, ir, 1)
999 kin(row, :) = 0.5_dp*tau(ia, ir, 1)
1001 density(row, :) = rho(ia, ir, 1:2)
1003 grad(row, idir, :) = drho(idir, ia, ir, 1:2)
1005 kin(row, :) = tau(ia, ir, 1:2)
1019 atomic_grid_size_bound_shape)
1036 atomic_grid_size_bound_shape_t)
1040 CALL torch_dict_insert(inputs,
"coarse_0_atomic_coords", coarse_0_atomic_coords_t)
1044 IF (.NOT. my_energy_only)
THEN
1045 NULLIFY (atom_coord_grad, density_grad, grad_grad, grid_coord_grad, kin_grad)
1047 IF (need_coord_grad)
THEN
1052 IF (
PRESENT(atom_force))
THEN
1053 atom_force(:) = atom_coord_grad(:, 1)
1055 atom_force(:) = atom_force(:) + grid_coord_grad(:, row)
1058 IF (
PRESENT(atom_virial))
THEN
1062 tmp = grid_coord_grad(idir, row)*coarse_0_atomic_coords(jdir, 1)
1063 atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
1069 tmp = atom_coord_grad(idir, 1)*coarse_0_atomic_coords(jdir, 1)
1070 atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
1076 grad_grad_t, kin_grad_t)
1086 vxc(ia, ir, 1:2) = density_grad(row, 1:2)
1088 vxg(idir, ia, ir, 1:2) = grad_grad(row, idir, 1:2)
1090 vtau(ia, ir, 1:2) = kin_grad(row, 1:2)
1092 vxc(ia, ir, 1) = 0.5_dp*(density_grad(row, 1) + density_grad(row, 2))
1094 vxg(idir, ia, ir, 1) = &
1095 0.5_dp*(grad_grad(row, idir, 1) + grad_grad(row, idir, 2))
1097 vtau(ia, ir, 1) = 0.5_dp*(kin_grad(row, 1) + kin_grad(row, 2))
1105 IF (need_coord_grad)
THEN
1122 DEALLOCATE (atomic_grid_size_bound_shape, atomic_grid_sizes, atomic_grid_weights, &
1123 coarse_0_atomic_coords, density, grad, grid_coords, grid_weights, kin)
1125 CALL omp_set_num_threads(omp_max_threads_restore)
1151 grid_coords, grid_weights, atomic_grid_weights, &
1152 atomic_grid_sizes, atomic_coords, exc, &
1153 density_grad_out, grad_grad_out, kin_grad_out, &
1154 grid_coord_grad_out, grid_weight_grad_out, &
1155 atomic_grid_weight_grad_out, atom_coord_grad_out)
1159 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :),
INTENT(IN) :: density, grid_coords, &
1161 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :),
INTENT(IN) :: grad
1162 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:),
INTENT(IN) :: grid_weights, atomic_grid_weights
1163 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:),
INTENT(IN) :: atomic_grid_sizes
1164 REAL(kind=
dp),
INTENT(OUT) :: exc
1165 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :),
INTENT(OUT),
OPTIONAL :: density_grad_out, &
1167 grid_coord_grad_out, &
1169 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :),
INTENT(OUT),
OPTIONAL :: grad_grad_out
1170 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT),
OPTIONAL :: grid_weight_grad_out, &
1171 atomic_grid_weight_grad_out
1173 CHARACTER(len=default_path_length) :: model_path
1174 INTEGER :: atom_begin, atom_count, chunk_max_rows, chunk_row_count, chunk_row_start, &
1175 ichunk, local_natom, local_nrow, max_grid_size, native_grid_cuda_device, &
1176 nchunks, omp_max_threads_restore, phase_handle, selected_cuda_device
1177 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: chunk_atom_begin, chunk_atom_count, &
1178 chunk_row_begin, chunk_row_counts
1179 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:, :) :: atomic_grid_size_bound_shape
1180 LOGICAL :: active_rank, native_grid_atom_chunks, native_grid_use_cuda, &
1181 need_coordinate_derivatives, need_derivatives
1182 REAL(kind=
dp) :: chunk_exc
1183 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
1184 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad, density_grad, &
1185 grid_coord_grad, kin_grad
1186 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad
1190 atomic_grid_sizes_t, &
1191 atomic_grid_sizes_chunk_t, &
1192 atomic_grid_weight_grad_t, &
1193 atomic_grid_weights_chunk_t, &
1194 atom_coord_grad_t, atomic_coords_chunk_t, &
1195 density_chunk_t, density_grad_t, &
1196 exc_tensor, grad_chunk_t, grad_grad_t, &
1197 grid_coord_grad_t, grid_coords_chunk_t, &
1198 grid_weight_grad_t, grid_weights_chunk_t, &
1199 kin_chunk_t, kin_grad_t
1201 atomic_grid_weights_local_t, &
1202 density_local_t, grad_local_t, &
1203 grid_coords_local_t, grid_weights_local_t, &
1206 density_t, grad_t, grid_coords_t, &
1207 grid_weights_t, kin_t
1209 cpassert(
ASSOCIATED(xc_section))
1210 cpassert(
SIZE(density, 1) ==
SIZE(grid_weights))
1211 cpassert(
SIZE(density, 1) ==
SIZE(atomic_grid_weights))
1212 cpassert(
SIZE(density, 1) ==
SIZE(grid_coords, 2))
1213 cpassert(
SIZE(density, 1) ==
SIZE(grad, 1))
1214 cpassert(
SIZE(density, 1) ==
SIZE(kin, 1))
1215 cpassert(
SIZE(density, 2) == 2)
1216 cpassert(
SIZE(grad, 2) == 3)
1217 cpassert(
SIZE(grad, 3) == 2)
1218 cpassert(
SIZE(kin, 2) == 2)
1219 cpassert(
SIZE(atomic_grid_sizes) ==
SIZE(atomic_coords, 2))
1220 cpassert(sum(atomic_grid_sizes) == int(
SIZE(density, 1), kind=
int_8))
1221 need_derivatives =
PRESENT(density_grad_out)
1222 cpassert(
PRESENT(grad_grad_out) .EQV. need_derivatives)
1223 cpassert(
PRESENT(kin_grad_out) .EQV. need_derivatives)
1224 need_coordinate_derivatives =
PRESENT(grid_coord_grad_out)
1225 cpassert(
PRESENT(grid_weight_grad_out) .EQV. need_coordinate_derivatives)
1226 cpassert(
PRESENT(atomic_grid_weight_grad_out) .EQV. need_coordinate_derivatives)
1227 cpassert(
PRESENT(atom_coord_grad_out) .EQV. need_coordinate_derivatives)
1228 cpassert((.NOT. need_coordinate_derivatives) .OR. need_derivatives)
1229 omp_max_threads_restore = omp_get_max_threads()
1231 local_nrow =
SIZE(density, 1)
1232 local_natom =
SIZE(atomic_grid_sizes)
1233 active_rank = local_natom > 0
1234 cpassert(active_rank .EQV. (local_nrow > 0))
1236 CALL get_skala_model_path(xc_section, model_path)
1238 cpassert(
ASSOCIATED(gauxc_section))
1241 i_val=native_grid_cuda_device)
1243 l_val=native_grid_atom_chunks)
1245 i_val=chunk_max_rows)
1246 IF (chunk_max_rows < -1)
THEN
1247 CALL cp_abort(__location__, &
1248 "GAUXC%NATIVE_GRID_ATOM_CHUNK_MAX_ROWS must be -1, zero, or positive.")
1250 IF (.NOT. native_grid_atom_chunks) chunk_max_rows = 0
1251 IF (chunk_max_rows == -1)
THEN
1252 chunk_max_rows = auto_atom_composite_chunk_max_rows(atomic_grid_sizes, group)
1255 selected_cuda_device = configure_native_grid_cuda( &
1256 native_grid_use_cuda, native_grid_cuda_device, group)
1258 IF (active_rank)
THEN
1259 CALL timeset(
"skala_atom_tensor_setup", phase_handle)
1260 CALL ensure_model_loaded(model_path, selected_cuda_device)
1261 CALL atom_composite_chunk_layout(atomic_grid_sizes, chunk_max_rows, &
1262 chunk_atom_begin, chunk_atom_count, &
1263 chunk_row_begin, chunk_row_counts)
1264 nchunks =
SIZE(chunk_atom_begin)
1265 cpassert(nchunks > 0)
1267 IF (native_grid_use_cuda)
THEN
1268 grid_coords_t => cached_atom_cuda_tensors%grid_coords_t
1269 grid_weights_t => cached_atom_cuda_tensors%grid_weights_t
1270 atomic_grid_weights_t => cached_atom_cuda_tensors%atomic_grid_weights_t
1271 atomic_coords_t => cached_atom_cuda_tensors%atomic_coords_t
1272 density_t => cached_atom_cuda_tensors%density_t
1273 grad_t => cached_atom_cuda_tensors%grad_t
1274 kin_t => cached_atom_cuda_tensors%kin_t
1276 grid_coords_t, grid_coords, need_coordinate_derivatives)
1278 grid_weights_t, grid_weights, need_coordinate_derivatives)
1280 atomic_grid_weights_t, atomic_grid_weights, need_coordinate_derivatives)
1282 atomic_coords_t, atomic_coords, need_coordinate_derivatives)
1287 grid_coords_t => grid_coords_local_t
1288 grid_weights_t => grid_weights_local_t
1289 atomic_grid_weights_t => atomic_grid_weights_local_t
1290 atomic_coords_t => atomic_coords_local_t
1291 density_t => density_local_t
1292 grad_t => grad_local_t
1293 kin_t => kin_local_t
1311 CALL timestop(phase_handle)
1313 DO ichunk = 1, nchunks
1314 atom_begin = chunk_atom_begin(ichunk)
1315 atom_count = chunk_atom_count(ichunk)
1316 chunk_row_start = chunk_row_begin(ichunk)
1317 chunk_row_count = chunk_row_counts(ichunk)
1318 max_grid_size = int(maxval(atomic_grid_sizes( &
1319 atom_begin:atom_begin + atom_count - 1)))
1320 ALLOCATE (atomic_grid_size_bound_shape(0, max_grid_size))
1321 atomic_grid_size_bound_shape = 0_int_8
1324 chunk_row_count, grid_coords_chunk_t)
1326 chunk_row_count, grid_weights_chunk_t)
1328 chunk_row_count, atomic_grid_weights_chunk_t)
1330 atom_count, atomic_grid_sizes_chunk_t)
1332 atom_count, atomic_coords_chunk_t)
1334 chunk_row_count, density_chunk_t)
1336 chunk_row_count, grad_chunk_t)
1338 chunk_row_count, kin_chunk_t)
1340 atomic_grid_size_bound_shape)
1346 CALL torch_dict_insert(inputs,
"atomic_grid_weights", atomic_grid_weights_chunk_t)
1349 atomic_grid_size_bound_shape_t)
1355 CALL timeset(
"skala_atom_torch_forward", phase_handle)
1357 exc_tensor, chunk_exc)
1358 CALL timestop(phase_handle)
1359 exc = exc + chunk_exc
1360 IF (need_derivatives)
THEN
1361 CALL timeset(
"skala_atom_torch_backward", phase_handle)
1363 CALL timestop(phase_handle)
1377 DEALLOCATE (atomic_grid_size_bound_shape)
1382 IF (need_derivatives)
THEN
1383 ALLOCATE (density_grad_out(local_nrow, 2), grad_grad_out(local_nrow, 3, 2), &
1384 kin_grad_out(local_nrow, 2))
1385 density_grad_out = 0.0_dp
1386 grad_grad_out = 0.0_dp
1387 kin_grad_out = 0.0_dp
1388 IF (active_rank)
THEN
1389 NULLIFY (density_grad, grad_grad, kin_grad)
1390 CALL timeset(
"skala_atom_grad_fetch", phase_handle)
1392 grad_grad_t, kin_grad_t)
1396 density_grad_out(:, :) = density_grad
1397 grad_grad_out(:, :, :) = grad_grad
1398 kin_grad_out(:, :) = kin_grad
1399 CALL timestop(phase_handle)
1402 IF (need_coordinate_derivatives)
THEN
1403 IF (active_rank)
CALL timeset(
"skala_atom_coord_grad_fetch", phase_handle)
1404 ALLOCATE (grid_coord_grad_out(3, local_nrow), grid_weight_grad_out(local_nrow), &
1405 atomic_grid_weight_grad_out(local_nrow), atom_coord_grad_out(3, local_natom))
1406 grid_coord_grad_out = 0.0_dp
1407 grid_weight_grad_out = 0.0_dp
1408 atomic_grid_weight_grad_out = 0.0_dp
1409 atom_coord_grad_out = 0.0_dp
1410 IF (active_rank)
THEN
1411 NULLIFY (atomic_grid_weight_grad, atom_coord_grad, grid_coord_grad, grid_weight_grad)
1420 grid_coord_grad_out(:, :) = grid_coord_grad
1421 grid_weight_grad_out(:) = grid_weight_grad
1422 atomic_grid_weight_grad_out(:) = atomic_grid_weight_grad
1423 atom_coord_grad_out(:, :) = atom_coord_grad
1428 CALL timestop(phase_handle)
1431 IF (active_rank)
THEN
1438 IF (active_rank)
THEN
1439 CALL timeset(
"skala_atom_tensor_release", phase_handle)
1440 IF (.NOT. native_grid_use_cuda)
THEN
1450 DEALLOCATE (chunk_atom_begin, chunk_atom_count, chunk_row_begin, chunk_row_counts)
1451 CALL timestop(phase_handle)
1454 CALL omp_set_num_threads(omp_max_threads_restore)
1464 FUNCTION auto_atom_composite_chunk_max_rows(atomic_grid_sizes, group)
RESULT(max_rows)
1465 INTEGER(KIND=int_8),
DIMENSION(:),
INTENT(IN) :: atomic_grid_sizes
1469 INTEGER :: local_max_atom_rows, local_natom, &
1470 local_padded_rows, max_rows
1472 local_padded_rows = 0
1473 local_natom =
SIZE(atomic_grid_sizes)
1474 IF (local_natom > 0)
THEN
1475 local_max_atom_rows = int(maxval(atomic_grid_sizes))
1476 IF (local_natom > atom_chunk_auto_max_rows .OR. &
1477 local_max_atom_rows > atom_chunk_auto_max_rows/local_natom)
THEN
1478 local_padded_rows = atom_chunk_auto_max_rows + 1
1480 local_padded_rows = local_natom*local_max_atom_rows
1483 CALL group%max(local_padded_rows)
1484 IF (local_padded_rows <= atom_chunk_auto_max_rows)
THEN
1488 max_rows = atom_chunk_auto_max_rows
1490 END FUNCTION auto_atom_composite_chunk_max_rows
1501 SUBROUTINE atom_composite_chunk_layout(atomic_grid_sizes, max_rows, atom_begin, atom_count, &
1502 row_begin, row_count)
1503 INTEGER(KIND=int_8),
ALLOCATABLE,
DIMENSION(:), &
1504 INTENT(IN) :: atomic_grid_sizes
1505 INTEGER,
INTENT(IN) :: max_rows
1506 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: atom_begin, atom_count, row_begin, &
1509 INTEGER :: atom_begin_tmp, atom_count_tmp, atom_rows, chunk_atoms, chunk_max_atom_rows, &
1510 iatom, insert_at, natom, nchunks, padded_rows_tmp, row_begin_tmp, row_count_tmp, rows, &
1512 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: padded_rows
1514 natom =
SIZE(atomic_grid_sizes)
1516 cpassert(all(atomic_grid_sizes > 0_int_8))
1517 IF (max_rows <= 0)
THEN
1518 ALLOCATE (atom_begin(1), atom_count(1), row_begin(1), row_count(1))
1520 atom_count(1) = natom
1522 row_count(1) = int(sum(atomic_grid_sizes))
1528 chunk_max_atom_rows = 0
1530 atom_rows = int(atomic_grid_sizes(iatom))
1531 IF (chunk_atoms > 0 .AND. &
1532 max(chunk_max_atom_rows, atom_rows) > max_rows/(chunk_atoms + 1))
THEN
1533 nchunks = nchunks + 1
1535 chunk_max_atom_rows = 0
1537 chunk_atoms = chunk_atoms + 1
1538 chunk_max_atom_rows = max(chunk_max_atom_rows, atom_rows)
1540 ALLOCATE (atom_begin(nchunks), atom_count(nchunks), row_begin(nchunks), row_count(nchunks))
1543 atom_begin(subchunk) = 1
1544 row_begin(subchunk) = 1
1546 chunk_max_atom_rows = 0
1549 atom_rows = int(atomic_grid_sizes(iatom))
1550 IF (chunk_atoms > 0 .AND. &
1551 max(chunk_max_atom_rows, atom_rows) > max_rows/(chunk_atoms + 1))
THEN
1552 atom_count(subchunk) = iatom - atom_begin(subchunk)
1553 row_count(subchunk) = rows
1554 subchunk = subchunk + 1
1555 atom_begin(subchunk) = iatom
1556 row_begin(subchunk) = row_begin(subchunk - 1) + row_count(subchunk - 1)
1558 chunk_max_atom_rows = 0
1561 chunk_atoms = chunk_atoms + 1
1562 chunk_max_atom_rows = max(chunk_max_atom_rows, atom_rows)
1563 rows = rows + atom_rows
1565 atom_count(subchunk) = natom - atom_begin(subchunk) + 1
1566 row_count(subchunk) = rows
1567 cpassert(subchunk == nchunks)
1569 ALLOCATE (padded_rows(nchunks))
1570 DO subchunk = 1, nchunks
1571 iatom = atom_begin(subchunk) + atom_count(subchunk) - 1
1572 padded_rows(subchunk) = atom_count(subchunk)* &
1573 int(maxval(atomic_grid_sizes(atom_begin(subchunk):iatom)))
1577 DO subchunk = 2, nchunks
1578 padded_rows_tmp = padded_rows(subchunk)
1579 atom_begin_tmp = atom_begin(subchunk)
1580 atom_count_tmp = atom_count(subchunk)
1581 row_begin_tmp = row_begin(subchunk)
1582 row_count_tmp = row_count(subchunk)
1583 insert_at = subchunk
1584 DO WHILE (insert_at > 1 .AND. padded_rows(insert_at - 1) < padded_rows_tmp)
1585 padded_rows(insert_at) = padded_rows(insert_at - 1)
1586 atom_begin(insert_at) = atom_begin(insert_at - 1)
1587 atom_count(insert_at) = atom_count(insert_at - 1)
1588 row_begin(insert_at) = row_begin(insert_at - 1)
1589 row_count(insert_at) = row_count(insert_at - 1)
1590 insert_at = insert_at - 1
1592 padded_rows(insert_at) = padded_rows_tmp
1593 atom_begin(insert_at) = atom_begin_tmp
1594 atom_count(insert_at) = atom_count_tmp
1595 row_begin(insert_at) = row_begin_tmp
1596 row_count(insert_at) = row_count_tmp
1598 DEALLOCATE (padded_rows)
1600 END SUBROUTINE atom_composite_chunk_layout
1609 SUBROUTINE add_explicit_coordinate_force(atom_force, features, atom_coord_grad_t, root_rank)
1610 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: atom_force
1613 LOGICAL,
INTENT(IN) :: root_rank
1615 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad
1617 NULLIFY (atom_coord_grad)
1621 cpassert(
SIZE(atom_force, 1) ==
SIZE(atom_coord_grad, 1))
1622 cpassert(
SIZE(atom_force, 2) ==
SIZE(atom_coord_grad, 2))
1623 atom_force(:, :) = atom_force(:, :) + atom_coord_grad(:, :)
1626 END SUBROUTINE add_explicit_coordinate_force
1638 SUBROUTINE add_smooth_partition_force(atom_force, features, particle_set, cell, rho_r, &
1639 grid_weight_grad_t, atomic_grid_weight_grad_t)
1640 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: atom_force
1646 atomic_grid_weight_grad_t
1648 INTEGER :: feature_begin, feature_end, feature_pos, &
1649 i, iatom, j, jatom, k, local_row, &
1651 INTEGER,
DIMENSION(2, 3) :: bo
1652 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: included
1653 REAL(kind=
dp) :: grid_base_weight, weight_grad
1654 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: weights
1655 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: atom_coords_pbc
1656 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
1657 REAL(kind=
dp),
DIMENSION(3) :: grid_point
1658 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
1660 NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
1662 CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
1666 natom =
SIZE(particle_set)
1667 cpassert(
SIZE(atom_force, 1) == 3)
1668 cpassert(
SIZE(atom_force, 2) == natom)
1669 ALLOCATE (atom_coords_pbc(3, natom), included(natom), weights(natom), &
1670 dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
1672 atom_coords_pbc(:, iatom) =
pbc(particle_set(iatom)%r, cell, positive_range=.true.)
1675 bo = rho_r(1)%pw_grid%bounds_local
1677 DO k = bo(1, 3), bo(2, 3)
1678 DO j = bo(1, 2), bo(2, 2)
1679 DO i = bo(1, 1), bo(2, 1)
1680 local_row = local_row + 1
1681 grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
1683 weights, included, dweights_datom, &
1685 feature_begin = features%local_feature_offsets(local_row)
1686 feature_end = features%local_feature_offsets(local_row + 1) - 1
1687 cpassert(feature_end - feature_begin + 1 == count(included))
1688 grid_base_weight = 0.0_dp
1689 DO feature_pos = feature_begin, feature_end
1690 row = features%local_feature_rows(feature_pos)
1691 grid_base_weight = grid_base_weight + features%grid_weights(row)
1693 feature_pos = feature_begin
1695 IF (.NOT. included(iatom)) cycle
1696 row = features%local_feature_rows(feature_pos)
1697 weight_grad = grid_base_weight*grid_weight_grad(row) + &
1698 rho_r(1)%pw_grid%dvol*atomic_grid_weight_grad(row)* &
1701 atom_force(:, jatom) = atom_force(:, jatom) + &
1702 weight_grad*dweights_datom(:, jatom, iatom)
1704 feature_pos = feature_pos + 1
1706 cpassert(feature_pos == feature_end + 1)
1710 cpassert(local_row == features%nflat_local)
1712 DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, weights)
1716 END SUBROUTINE add_smooth_partition_force
1728 SUBROUTINE build_smooth_partition_virial(virial_xc, features, particle_set, cell, rho_r, &
1729 grid_weight_grad_t, atomic_grid_weight_grad_t)
1730 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
1736 atomic_grid_weight_grad_t
1738 INTEGER :: feature_begin, feature_end, feature_pos, &
1739 i, iatom, idir, j, jdir, k, local_row, &
1741 INTEGER,
DIMENSION(2, 3) :: bo
1742 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: included
1743 REAL(kind=
dp) :: grid_base_weight, tmp, weight_grad
1744 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: weights
1745 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: atom_coords_pbc
1746 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
1747 REAL(kind=
dp),
DIMENSION(3) :: grid_point
1748 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
1750 NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
1752 CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
1756 natom =
SIZE(particle_set)
1757 ALLOCATE (atom_coords_pbc(3, natom), included(natom), weights(natom), &
1758 dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
1760 atom_coords_pbc(:, iatom) =
pbc(particle_set(iatom)%r, cell, positive_range=.true.)
1763 bo = rho_r(1)%pw_grid%bounds_local
1765 DO k = bo(1, 3), bo(2, 3)
1766 DO j = bo(1, 2), bo(2, 2)
1767 DO i = bo(1, 1), bo(2, 1)
1768 local_row = local_row + 1
1769 grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
1771 weights, included, dweights_datom, &
1773 feature_begin = features%local_feature_offsets(local_row)
1774 feature_end = features%local_feature_offsets(local_row + 1) - 1
1775 cpassert(feature_end - feature_begin + 1 == count(included))
1776 grid_base_weight = 0.0_dp
1777 DO feature_pos = feature_begin, feature_end
1778 row = features%local_feature_rows(feature_pos)
1779 grid_base_weight = grid_base_weight + features%grid_weights(row)
1781 feature_pos = feature_begin
1783 IF (.NOT. included(iatom)) cycle
1784 row = features%local_feature_rows(feature_pos)
1785 weight_grad = grid_base_weight*grid_weight_grad(row) + &
1786 rho_r(1)%pw_grid%dvol*atomic_grid_weight_grad(row)* &
1790 tmp = weight_grad*dweights_dstrain(idir, jdir, iatom)
1791 virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
1792 IF (idir /= jdir) virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
1795 feature_pos = feature_pos + 1
1797 cpassert(feature_pos == feature_end + 1)
1801 cpassert(local_row == features%nflat_local)
1803 DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, weights)
1807 END SUBROUTINE build_smooth_partition_virial
1815 FUNCTION native_grid_coordinate(pw_grid, index)
RESULT(coord)
1817 INTEGER,
DIMENSION(3),
INTENT(IN) :: index
1818 REAL(kind=
dp),
DIMENSION(3) :: coord
1820 INTEGER,
DIMENSION(3) :: relative_index
1822 relative_index = index - pw_grid%bounds(1, :)
1823 coord = real(relative_index(1), kind=
dp)*pw_grid%dh(:, 1) + &
1824 REAL(relative_index(2), kind=
dp)*pw_grid%dh(:, 2) + &
1825 REAL(relative_index(3), kind=
dp)*pw_grid%dh(:, 3)
1827 END FUNCTION native_grid_coordinate
1841 SUBROUTINE evaluate_atom_subchunks(features, group, max_rows, compute_grads, exc, &
1842 density_grad, grad_grad, kin_grad, collapse_spin_grads)
1846 INTEGER,
INTENT(IN) :: max_rows
1847 LOGICAL,
INTENT(IN) :: compute_grads, collapse_spin_grads
1848 REAL(kind=
dp),
INTENT(OUT) :: exc
1849 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
1850 INTENT(OUT) :: density_grad, kin_grad
1851 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
1852 INTENT(OUT) :: grad_grad
1854 INTEGER :: isubchunk, nroute_grad_per_point, &
1855 nroute_recv_points, nroute_send_points, &
1856 nsubchunks, phase_handle, subphase_handle
1857 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: route_grad_return_recv_counts, &
1858 route_grad_return_recv_displs, &
1859 route_grad_return_send_counts, &
1860 route_grad_return_send_displs, &
1861 subchunk_atom_begin, &
1862 subchunk_atom_count, &
1863 subchunk_row_begin, &
1865 REAL(kind=
dp) :: subchunk_exc
1866 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: recv_grad_buffer, send_grad_buffer
1870 cpassert(features%uses_atom_chunks)
1871 cpassert(max_rows > 0)
1873 subchunk_row_begin, subchunk_row_count)
1874 nsubchunks =
SIZE(subchunk_atom_begin)
1877 IF (compute_grads)
THEN
1878 cpassert(features%uses_atom_chunk_routing)
1879 nroute_recv_points = sum(features%route_point_recv_counts)
1880 nroute_send_points =
SIZE(features%route_send_local_rows)
1881 cpassert(sum(features%route_point_send_counts) == nroute_send_points)
1882 cpassert(
SIZE(features%route_chunk_offsets) == nroute_recv_points + 1)
1883 nroute_grad_per_point = ngrad_per_point
1884 IF (collapse_spin_grads) nroute_grad_per_point = ncollapsed_grad_per_point
1885 ALLOCATE (send_grad_buffer(max(1, nroute_grad_per_point*nroute_recv_points)), &
1886 recv_grad_buffer(max(1, nroute_grad_per_point*nroute_send_points)), &
1887 route_grad_return_send_counts(
SIZE(features%route_point_recv_counts)), &
1888 route_grad_return_send_displs(
SIZE(features%route_point_recv_displs)), &
1889 route_grad_return_recv_counts(
SIZE(features%route_point_send_counts)), &
1890 route_grad_return_recv_displs(
SIZE(features%route_point_send_displs)))
1891 route_grad_return_send_counts(:) = &
1892 nroute_grad_per_point*features%route_point_recv_counts
1893 route_grad_return_send_displs(:) = &
1894 nroute_grad_per_point*features%route_point_recv_displs
1895 route_grad_return_recv_counts(:) = &
1896 nroute_grad_per_point*features%route_point_send_counts
1897 route_grad_return_recv_displs(:) = &
1898 nroute_grad_per_point*features%route_point_send_displs
1901 CALL timeset(
"skala_gpw_atom_subchunks", phase_handle)
1902 DO isubchunk = 1, nsubchunks
1903 CALL timeset(
"skala_gpw_atom_subchunk_build", subphase_handle)
1905 subchunk_atom_begin(isubchunk), &
1906 subchunk_atom_count(isubchunk), &
1907 subchunk_row_begin(isubchunk), &
1908 subchunk_row_count(isubchunk), &
1910 CALL timestop(subphase_handle)
1911 CALL timeset(
"skala_gpw_atom_subchunk_forward", subphase_handle)
1913 subchunk%grid_weights_t, subchunk_exc_tensor, &
1915 CALL timestop(subphase_handle)
1916 exc = exc + subchunk_exc
1917 IF (compute_grads)
THEN
1918 CALL timeset(
"skala_gpw_atom_subchunk_backward", subphase_handle)
1920 CALL timestop(subphase_handle)
1922 CALL timeset(
"skala_gpw_atom_subchunk_release", subphase_handle)
1925 CALL timestop(subphase_handle)
1927 IF (compute_grads .AND. features%chunk_feature_count > 0)
THEN
1928 CALL timeset(
"skala_gpw_atom_subchunk_grad_pack", subphase_handle)
1929 CALL pack_atom_chunk_grads(features, send_grad_buffer, .true., collapse_spin_grads)
1930 CALL timestop(subphase_handle)
1932 CALL timestop(phase_handle)
1934 IF (compute_grads)
THEN
1935 CALL timeset(
"skala_gpw_grad_route_comm", phase_handle)
1936 CALL group%alltoall(send_grad_buffer, route_grad_return_send_counts, &
1937 route_grad_return_send_displs, recv_grad_buffer, &
1938 route_grad_return_recv_counts, route_grad_return_recv_displs)
1939 CALL timestop(phase_handle)
1941 CALL timeset(
"skala_gpw_grad_route_scatter", phase_handle)
1942 CALL scatter_routed_atom_chunk_grads(features, recv_grad_buffer, collapse_spin_grads, &
1943 density_grad, grad_grad, kin_grad)
1944 CALL timestop(phase_handle)
1946 DEALLOCATE (recv_grad_buffer, route_grad_return_recv_counts, &
1947 route_grad_return_recv_displs, route_grad_return_send_counts, &
1948 route_grad_return_send_displs, send_grad_buffer)
1950 DEALLOCATE (subchunk_atom_begin, subchunk_atom_count, subchunk_row_begin, subchunk_row_count)
1952 END SUBROUTINE evaluate_atom_subchunks
1960 FUNCTION auto_atom_chunk_max_rows(features, group)
RESULT(max_rows)
1966 INTEGER :: local_rows_max, target_rows
1968 local_rows_max = features%chunk_feature_count
1969 CALL group%max(local_rows_max)
1970 IF (local_rows_max <= 0)
THEN
1975 IF (group%num_pe > 1)
THEN
1976 target_rows = ceiling(real(local_rows_max, kind=
dp)/2.0_dp)
1977 max_rows = atom_chunk_auto_row_quantum* &
1978 ((target_rows + atom_chunk_auto_row_quantum - 1)/atom_chunk_auto_row_quantum)
1980 target_rows = nint(real(local_rows_max, kind=
dp)/4.0_dp)
1981 max_rows = atom_chunk_auto_row_quantum* &
1982 max(1, nint(real(target_rows, kind=
dp)/ &
1983 REAL(atom_chunk_auto_row_quantum, kind=
dp)))
1985 max_rows = max(atom_chunk_auto_min_rows, min(atom_chunk_auto_max_rows, max_rows))
1987 END FUNCTION auto_atom_chunk_max_rows
1996 SUBROUTINE fetch_local_feature_grads(features, density_grad, grad_grad, kin_grad)
1998 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
1999 INTENT(OUT) :: density_grad
2000 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2001 INTENT(OUT) :: grad_grad
2002 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2003 INTENT(OUT) :: kin_grad
2005 INTEGER :: feature_pos, i, j, k, local_row, row
2006 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: density_grad_all, kin_grad_all
2007 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad_all
2010 NULLIFY (density_grad_all, grad_grad_all, kin_grad_all)
2011 CALL get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2012 density_grad_all, grad_grad_all, kin_grad_all)
2013 cpassert(
SIZE(density_grad_all, 1) == features%nflat)
2014 cpassert(
SIZE(density_grad_all, 2) == 2)
2015 cpassert(
SIZE(grad_grad_all, 1) == features%nflat)
2016 cpassert(
SIZE(grad_grad_all, 2) == 3)
2017 cpassert(
SIZE(grad_grad_all, 3) == 2)
2018 cpassert(
SIZE(kin_grad_all, 1) == features%nflat)
2019 cpassert(
SIZE(kin_grad_all, 2) == 2)
2021 ALLOCATE (density_grad(features%nflat_local, 2), &
2022 grad_grad(features%nflat_local, 3, 2), &
2023 kin_grad(features%nflat_local, 2))
2024 density_grad = 0.0_dp
2028 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2029 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2030 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2031 local_row = local_row + 1
2032 DO feature_pos = features%local_feature_offsets(local_row), &
2033 features%local_feature_offsets(local_row + 1) - 1
2034 row = features%local_feature_rows(feature_pos)
2035 cpassert(row >= 1 .AND. row <= features%nflat)
2036 density_grad(local_row, :) = density_grad(local_row, :) + &
2037 density_grad_all(row, :)
2038 grad_grad(local_row, :, :) = grad_grad(local_row, :, :) + &
2039 grad_grad_all(row, :, :)
2040 kin_grad(local_row, :) = kin_grad(local_row, :) + kin_grad_all(row, :)
2045 cpassert(local_row == features%nflat_local)
2051 END SUBROUTINE fetch_local_feature_grads
2060 SUBROUTINE pack_atom_chunk_grads(features, TARGET, route_to_return_positions, &
2061 collapse_spin_grads)
2063 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
2064 INTENT(INOUT) ::
target
2065 LOGICAL,
INTENT(IN) :: route_to_return_positions
2066 LOGICAL,
INTENT(IN),
OPTIONAL :: collapse_spin_grads
2068 INTEGER :: base, feature_pos, irow, &
2069 ngrad_buffer_per_point, point_pos, &
2071 LOGICAL :: my_collapse_spin_grads
2072 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: chunk_density_grad, chunk_kin_grad
2073 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: chunk_grad_grad
2076 my_collapse_spin_grads = .false.
2077 IF (
PRESENT(collapse_spin_grads)) my_collapse_spin_grads = collapse_spin_grads
2078 ngrad_buffer_per_point = ngrad_per_point
2079 IF (my_collapse_spin_grads) ngrad_buffer_per_point = ncollapsed_grad_per_point
2081 NULLIFY (chunk_density_grad, chunk_grad_grad, chunk_kin_grad)
2082 CALL get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2083 chunk_density_grad, chunk_grad_grad, chunk_kin_grad)
2084 cpassert(mod(
SIZE(
TARGET), ngrad_buffer_per_point) == 0)
2085 target_points =
SIZE(
TARGET)/ngrad_buffer_per_point
2086 cpassert(
SIZE(chunk_density_grad, 1) == features%chunk_feature_count)
2087 cpassert(
SIZE(chunk_grad_grad, 1) == features%chunk_feature_count)
2088 cpassert(
SIZE(chunk_grad_grad, 2) == 3)
2089 cpassert(
SIZE(chunk_kin_grad, 1) == features%chunk_feature_count)
2090 IF (features%uses_collapsed_rks_dynamic)
THEN
2091 cpassert(my_collapse_spin_grads)
2092 cpassert(
SIZE(chunk_density_grad, 2) == 1)
2093 cpassert(
SIZE(chunk_grad_grad, 3) == 1)
2094 cpassert(
SIZE(chunk_kin_grad, 2) == 1)
2096 cpassert(
SIZE(chunk_density_grad, 2) == 2)
2097 cpassert(
SIZE(chunk_grad_grad, 3) == 2)
2098 cpassert(
SIZE(chunk_kin_grad, 2) == 2)
2101 IF (route_to_return_positions)
THEN
2102 cpassert(target_points ==
SIZE(features%route_chunk_offsets) - 1)
2107 DO point_pos = 1, target_points
2108 base = ngrad_buffer_per_point*(point_pos - 1)
2109 target(base + 1:base + ngrad_buffer_per_point) = 0.0_dp
2110 DO feature_pos = features%route_chunk_offsets(point_pos), &
2111 features%route_chunk_offsets(point_pos + 1) - 1
2112 irow = features%route_chunk_rows(feature_pos)
2113 cpassert(irow >= 1 .AND. irow <= features%chunk_feature_count)
2114 IF (my_collapse_spin_grads)
THEN
2115 IF (features%uses_collapsed_rks_dynamic)
THEN
2116 target(base + 1) = target(base + 1) + &
2117 0.5_dp*chunk_density_grad(irow, 1)
2118 target(base + 2) = target(base + 2) + &
2119 0.5_dp*chunk_grad_grad(irow, 1, 1)
2120 target(base + 3) = target(base + 3) + &
2121 0.5_dp*chunk_grad_grad(irow, 2, 1)
2122 target(base + 4) = target(base + 4) + &
2123 0.5_dp*chunk_grad_grad(irow, 3, 1)
2124 target(base + 5) = target(base + 5) + &
2125 0.5_dp*chunk_kin_grad(irow, 1)
2127 target(base + 1) = target(base + 1) + &
2128 0.5_dp*(chunk_density_grad(irow, 1) + &
2129 chunk_density_grad(irow, 2))
2130 target(base + 2) = target(base + 2) + &
2131 0.5_dp*(chunk_grad_grad(irow, 1, 1) + &
2132 chunk_grad_grad(irow, 1, 2))
2133 target(base + 3) = target(base + 3) + &
2134 0.5_dp*(chunk_grad_grad(irow, 2, 1) + &
2135 chunk_grad_grad(irow, 2, 2))
2136 target(base + 4) = target(base + 4) + &
2137 0.5_dp*(chunk_grad_grad(irow, 3, 1) + &
2138 chunk_grad_grad(irow, 3, 2))
2139 target(base + 5) = target(base + 5) + &
2140 0.5_dp*(chunk_kin_grad(irow, 1) + &
2141 chunk_kin_grad(irow, 2))
2144 target(base + 1:base + 2) = target(base + 1:base + 2) + &
2145 chunk_density_grad(irow, :)
2146 target(base + 3) = target(base + 3) + chunk_grad_grad(irow, 1, 1)
2147 target(base + 4) = target(base + 4) + chunk_grad_grad(irow, 2, 1)
2148 target(base + 5) = target(base + 5) + chunk_grad_grad(irow, 3, 1)
2149 target(base + 6) = target(base + 6) + chunk_grad_grad(irow, 1, 2)
2150 target(base + 7) = target(base + 7) + chunk_grad_grad(irow, 2, 2)
2151 target(base + 8) = target(base + 8) + chunk_grad_grad(irow, 3, 2)
2152 target(base + 9:base + 10) = target(base + 9:base + 10) + &
2153 chunk_kin_grad(irow, :)
2159 cpassert(target_points >= features%chunk_feature_count)
2164 DO irow = 1, features%chunk_feature_count
2165 base = ngrad_buffer_per_point*(irow - 1)
2166 IF (my_collapse_spin_grads)
THEN
2167 IF (features%uses_collapsed_rks_dynamic)
THEN
2168 target(base + 1) = 0.5_dp*chunk_density_grad(irow, 1)
2169 target(base + 2) = 0.5_dp*chunk_grad_grad(irow, 1, 1)
2170 target(base + 3) = 0.5_dp*chunk_grad_grad(irow, 2, 1)
2171 target(base + 4) = 0.5_dp*chunk_grad_grad(irow, 3, 1)
2172 target(base + 5) = 0.5_dp*chunk_kin_grad(irow, 1)
2174 target(base + 1) = 0.5_dp*(chunk_density_grad(irow, 1) + &
2175 chunk_density_grad(irow, 2))
2176 target(base + 2) = 0.5_dp*(chunk_grad_grad(irow, 1, 1) + &
2177 chunk_grad_grad(irow, 1, 2))
2178 target(base + 3) = 0.5_dp*(chunk_grad_grad(irow, 2, 1) + &
2179 chunk_grad_grad(irow, 2, 2))
2180 target(base + 4) = 0.5_dp*(chunk_grad_grad(irow, 3, 1) + &
2181 chunk_grad_grad(irow, 3, 2))
2182 target(base + 5) = 0.5_dp*(chunk_kin_grad(irow, 1) + &
2183 chunk_kin_grad(irow, 2))
2186 target(base + 1:base + 2) = chunk_density_grad(irow, :)
2187 target(base + 3) = chunk_grad_grad(irow, 1, 1)
2188 target(base + 4) = chunk_grad_grad(irow, 2, 1)
2189 target(base + 5) = chunk_grad_grad(irow, 3, 1)
2190 target(base + 6) = chunk_grad_grad(irow, 1, 2)
2191 target(base + 7) = chunk_grad_grad(irow, 2, 2)
2192 target(base + 8) = chunk_grad_grad(irow, 3, 2)
2193 target(base + 9:base + 10) = chunk_kin_grad(irow, :)
2203 END SUBROUTINE pack_atom_chunk_grads
2214 SUBROUTINE scatter_routed_atom_chunk_grads(features, recv_grad_buffer, collapse_spin_grads, &
2215 density_grad, grad_grad, kin_grad)
2217 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: recv_grad_buffer
2218 LOGICAL,
INTENT(IN) :: collapse_spin_grads
2219 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2220 INTENT(OUT) :: density_grad
2221 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2222 INTENT(OUT) :: grad_grad
2223 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2224 INTENT(OUT) :: kin_grad
2226 INTEGER :: base, local_row, nflat_local, &
2227 nroute_grad_per_point, nroute_points, &
2228 point_pos, row_route_pos
2230 nflat_local = features%nflat_local
2231 nroute_points =
SIZE(features%route_send_local_rows)
2232 nroute_grad_per_point = ngrad_per_point
2233 IF (collapse_spin_grads) nroute_grad_per_point = ncollapsed_grad_per_point
2234 cpassert(
SIZE(recv_grad_buffer) >= nroute_grad_per_point*nroute_points)
2235 ALLOCATE (density_grad(nflat_local, 2), grad_grad(nflat_local, 3, 2), &
2236 kin_grad(nflat_local, 2))
2242 DO local_row = 1, nflat_local
2243 density_grad(local_row, :) = 0.0_dp
2244 grad_grad(local_row, :, :) = 0.0_dp
2245 kin_grad(local_row, :) = 0.0_dp
2246 DO row_route_pos = features%route_row_offsets(local_row), &
2247 features%route_row_offsets(local_row + 1) - 1
2248 point_pos = features%route_row_positions(row_route_pos)
2249 cpassert(point_pos >= 1 .AND. point_pos <= nroute_points)
2250 base = nroute_grad_per_point*(point_pos - 1)
2251 IF (collapse_spin_grads)
THEN
2252 density_grad(local_row, :) = density_grad(local_row, :) + &
2253 recv_grad_buffer(base + 1)
2254 grad_grad(local_row, 1, :) = grad_grad(local_row, 1, :) + &
2255 recv_grad_buffer(base + 2)
2256 grad_grad(local_row, 2, :) = grad_grad(local_row, 2, :) + &
2257 recv_grad_buffer(base + 3)
2258 grad_grad(local_row, 3, :) = grad_grad(local_row, 3, :) + &
2259 recv_grad_buffer(base + 4)
2260 kin_grad(local_row, :) = kin_grad(local_row, :) + recv_grad_buffer(base + 5)
2262 density_grad(local_row, :) = density_grad(local_row, :) + &
2263 recv_grad_buffer(base + 1:base + 2)
2264 grad_grad(local_row, 1, 1) = grad_grad(local_row, 1, 1) + &
2265 recv_grad_buffer(base + 3)
2266 grad_grad(local_row, 2, 1) = grad_grad(local_row, 2, 1) + &
2267 recv_grad_buffer(base + 4)
2268 grad_grad(local_row, 3, 1) = grad_grad(local_row, 3, 1) + &
2269 recv_grad_buffer(base + 5)
2270 grad_grad(local_row, 1, 2) = grad_grad(local_row, 1, 2) + &
2271 recv_grad_buffer(base + 6)
2272 grad_grad(local_row, 2, 2) = grad_grad(local_row, 2, 2) + &
2273 recv_grad_buffer(base + 7)
2274 grad_grad(local_row, 3, 2) = grad_grad(local_row, 3, 2) + &
2275 recv_grad_buffer(base + 8)
2276 kin_grad(local_row, :) = kin_grad(local_row, :) + &
2277 recv_grad_buffer(base + 9:base + 10)
2283 END SUBROUTINE scatter_routed_atom_chunk_grads
2295 SUBROUTINE get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2296 density_grad, grad_grad, kin_grad)
2298 TYPE(
torch_tensor_type),
INTENT(INOUT) :: density_grad_t, grad_grad_t, kin_grad_t
2299 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: density_grad
2300 REAL(kind=
dp),
DIMENSION(:, :, :),
POINTER :: grad_grad
2301 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: kin_grad
2303 NULLIFY (density_grad, grad_grad, kin_grad)
2305 density_grad_t, grad_grad_t, kin_grad_t)
2310 END SUBROUTINE get_feature_grad_views
2320 SUBROUTINE fetch_and_gather_atom_chunk_grads(features, group, density_grad, grad_grad, &
2325 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2326 INTENT(OUT) :: density_grad, kin_grad
2327 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2328 INTENT(OUT) :: grad_grad
2330 INTEGER :: base, feature_pos, i, j, k, local_row, &
2331 nflat_local, nroute_grad_per_point, &
2332 nroute_recv_points, nroute_send_points, &
2334 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: route_grad_return_recv_counts, &
2335 route_grad_return_recv_displs, &
2336 route_grad_return_send_counts, &
2337 route_grad_return_send_displs
2338 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: chunk_grad_buffer, global_grad_buffer, &
2339 recv_grad_buffer, send_grad_buffer
2341 cpassert(features%uses_atom_chunks)
2343 nflat_local = features%nflat_local
2344 IF (features%uses_atom_chunk_routing)
THEN
2345 nroute_recv_points = sum(features%route_point_recv_counts)
2346 nroute_send_points =
SIZE(features%route_send_local_rows)
2347 cpassert(sum(features%route_point_send_counts) == nroute_send_points)
2348 cpassert(
SIZE(features%route_chunk_offsets) == nroute_recv_points + 1)
2350 nroute_grad_per_point = ngrad_per_point
2351 IF (features%uses_collapsed_rks_dynamic)
THEN
2352 nroute_grad_per_point = ncollapsed_grad_per_point
2354 ALLOCATE (send_grad_buffer(max(1, nroute_grad_per_point*nroute_recv_points)), &
2355 recv_grad_buffer(max(1, nroute_grad_per_point*nroute_send_points)), &
2356 route_grad_return_send_counts(
SIZE(features%route_point_recv_counts)), &
2357 route_grad_return_send_displs(
SIZE(features%route_point_recv_displs)), &
2358 route_grad_return_recv_counts(
SIZE(features%route_point_send_counts)), &
2359 route_grad_return_recv_displs(
SIZE(features%route_point_send_displs)))
2360 route_grad_return_send_counts(:) = &
2361 nroute_grad_per_point*features%route_point_recv_counts
2362 route_grad_return_send_displs(:) = &
2363 nroute_grad_per_point*features%route_point_recv_displs
2364 route_grad_return_recv_counts(:) = &
2365 nroute_grad_per_point*features%route_point_send_counts
2366 route_grad_return_recv_displs(:) = &
2367 nroute_grad_per_point*features%route_point_send_displs
2369 IF (features%chunk_feature_count > 0)
THEN
2370 CALL timeset(
"skala_gpw_grad_torch_pack", phase_handle)
2371 CALL pack_atom_chunk_grads(features, send_grad_buffer, .true., &
2372 features%uses_collapsed_rks_dynamic)
2373 CALL timestop(phase_handle)
2376 CALL timeset(
"skala_gpw_grad_route_comm", phase_handle)
2377 CALL group%alltoall(send_grad_buffer, route_grad_return_send_counts, &
2378 route_grad_return_send_displs, recv_grad_buffer, &
2379 route_grad_return_recv_counts, route_grad_return_recv_displs)
2380 CALL timestop(phase_handle)
2382 CALL timeset(
"skala_gpw_grad_route_scatter", phase_handle)
2383 CALL scatter_routed_atom_chunk_grads(features, recv_grad_buffer, &
2384 features%uses_collapsed_rks_dynamic, &
2385 density_grad, grad_grad, kin_grad)
2386 CALL timestop(phase_handle)
2388 DEALLOCATE (recv_grad_buffer, route_grad_return_recv_counts, &
2389 route_grad_return_recv_displs, route_grad_return_send_counts, &
2390 route_grad_return_send_displs, send_grad_buffer)
2392 ALLOCATE (chunk_grad_buffer(max(1, ngrad_per_point*features%chunk_feature_count)), &
2393 global_grad_buffer(ngrad_per_point*features%nflat))
2394 IF (features%chunk_feature_count > 0)
THEN
2395 CALL timeset(
"skala_gpw_grad_torch_pack", phase_handle)
2396 CALL pack_atom_chunk_grads(features, chunk_grad_buffer, .false.)
2397 CALL timestop(phase_handle)
2400 CALL timeset(
"skala_gpw_grad_allgatherv", phase_handle)
2401 CALL group%allgatherv(chunk_grad_buffer, global_grad_buffer, &
2402 features%chunk_grad_counts, features%chunk_grad_displs)
2403 CALL timestop(phase_handle)
2405 CALL timeset(
"skala_gpw_grad_scatter", phase_handle)
2406 ALLOCATE (density_grad(nflat_local, 2), grad_grad(nflat_local, 3, 2), &
2407 kin_grad(nflat_local, 2))
2408 density_grad = 0.0_dp
2412 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2413 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2414 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2415 local_row = local_row + 1
2416 DO feature_pos = features%local_feature_offsets(local_row), &
2417 features%local_feature_offsets(local_row + 1) - 1
2418 row = features%local_feature_rows(feature_pos)
2419 cpassert(row >= 1 .AND. row <= features%nflat)
2420 base = ngrad_per_point*(row - 1)
2421 density_grad(local_row, :) = density_grad(local_row, :) + &
2422 global_grad_buffer(base + 1:base + 2)
2423 grad_grad(local_row, 1, 1) = grad_grad(local_row, 1, 1) + &
2424 global_grad_buffer(base + 3)
2425 grad_grad(local_row, 2, 1) = grad_grad(local_row, 2, 1) + &
2426 global_grad_buffer(base + 4)
2427 grad_grad(local_row, 3, 1) = grad_grad(local_row, 3, 1) + &
2428 global_grad_buffer(base + 5)
2429 grad_grad(local_row, 1, 2) = grad_grad(local_row, 1, 2) + &
2430 global_grad_buffer(base + 6)
2431 grad_grad(local_row, 2, 2) = grad_grad(local_row, 2, 2) + &
2432 global_grad_buffer(base + 7)
2433 grad_grad(local_row, 3, 2) = grad_grad(local_row, 3, 2) + &
2434 global_grad_buffer(base + 8)
2435 kin_grad(local_row, :) = kin_grad(local_row, :) + &
2436 global_grad_buffer(base + 9:base + 10)
2441 CALL timestop(phase_handle)
2442 DEALLOCATE (chunk_grad_buffer, global_grad_buffer)
2446 END SUBROUTINE fetch_and_gather_atom_chunk_grads
2455 SUBROUTINE build_virial_from_feature_grads(virial_xc, rho_set, rho_r, grad_grad)
2456 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
2459 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: grad_grad
2461 INTEGER :: i, idir, ipt, ispin, j, jdir, k, nspins
2462 INTEGER,
DIMENSION(2, 3) :: bo
2463 REAL(kind=
dp) :: grad_i, tmp
2466 nspins =
SIZE(rho_r)
2467 bo = rho_r(1)%pw_grid%bounds_local
2470 IF (nspins == 1)
THEN
2472 DO k = bo(1, 3), bo(2, 3)
2473 DO j = bo(1, 2), bo(2, 2)
2474 DO i = bo(1, 1), bo(2, 1)
2477 grad_i = 0.5_dp*(grad_grad(ipt, idir, 1) + grad_grad(ipt, idir, 2))
2479 tmp = -grad_i*drho(jdir)%array(i, j, k)
2480 virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2488 DO k = bo(1, 3), bo(2, 3)
2489 DO j = bo(1, 2), bo(2, 2)
2490 DO i = bo(1, 1), bo(2, 1)
2496 IF (ispin == 1)
THEN
2497 tmp = tmp - grad_grad(ipt, idir, ispin)*drhoa(jdir)%array(i, j, k)
2499 tmp = tmp - grad_grad(ipt, idir, ispin)*drhob(jdir)%array(i, j, k)
2502 virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2510 END SUBROUTINE build_virial_from_feature_grads
2518 SUBROUTINE print_virial_delta(label, delta, root_rank)
2519 CHARACTER(LEN=*),
INTENT(IN) :: label
2520 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(IN) :: delta
2521 LOGICAL,
INTENT(IN) :: root_rank
2525 IF (.NOT. root_rank)
RETURN
2528 WRITE (iw,
"(T2,A,1X,A)")
"SKALA_GPW| XC virial contribution", trim(label)
2530 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW|", delta(i, 1:3)
2533 END SUBROUTINE print_virial_delta
2544 SUBROUTINE build_static_coordinate_virial(virial_xc, features, atom_coord_grad_t, &
2545 grid_coord_grad_t, root_rank, print_components)
2546 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
2549 LOGICAL,
INTENT(IN) :: root_rank
2550 LOGICAL,
INTENT(IN),
OPTIONAL :: print_components
2552 INTEGER :: feature_pos, i, iatom, idir, iw, j, &
2553 jdir, k, local_row, row
2554 LOGICAL :: my_print_components
2555 REAL(kind=
dp) :: tmp
2556 REAL(kind=
dp),
DIMENSION(3) :: atom_grad_sum, grid_grad_sum
2557 REAL(kind=
dp),
DIMENSION(3, 3) :: atom_virial, grid_virial
2558 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: atom_coord_grad, grid_coord_grad
2560 my_print_components = .false.
2561 IF (
PRESENT(print_components)) my_print_components = print_components
2563 NULLIFY (atom_coord_grad, grid_coord_grad)
2568 grid_virial = 0.0_dp
2569 atom_virial = 0.0_dp
2570 grid_grad_sum = 0.0_dp
2571 atom_grad_sum = 0.0_dp
2573 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2574 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2575 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2576 local_row = local_row + 1
2577 DO feature_pos = features%local_feature_offsets(local_row), &
2578 features%local_feature_offsets(local_row + 1) - 1
2579 row = features%local_feature_rows(feature_pos)
2580 grid_grad_sum(:) = grid_grad_sum(:) + grid_coord_grad(:, row)
2583 tmp = grid_coord_grad(idir, row)*features%grid_coords(jdir, row)
2584 grid_virial(idir, jdir) = grid_virial(idir, jdir) + tmp
2585 virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
2592 cpassert(local_row == features%nflat_local)
2595 DO iatom = 1,
SIZE(features%coarse_0_atomic_coords, 2)
2596 atom_grad_sum(:) = atom_grad_sum(:) + atom_coord_grad(:, iatom)
2599 tmp = atom_coord_grad(idir, iatom)*features%coarse_0_atomic_coords(jdir, iatom)
2600 atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
2601 virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
2607 IF (my_print_components .AND. root_rank)
THEN
2610 CALL print_virial_delta(
"static-grid", grid_virial, .true.)
2611 CALL print_virial_delta(
"static-atom", atom_virial, .true.)
2612 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW| XC coordinate gradient grid sum", &
2614 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW| XC coordinate gradient atom sum", &
2616 WRITE (iw,
"(T2,A,1X,3ES20.10)")
"SKALA_GPW| XC coordinate gradient total sum", &
2617 grid_grad_sum + atom_grad_sum
2623 END SUBROUTINE build_static_coordinate_virial
2635 SUBROUTINE build_weight_virial(virial_xc, features, exc, grid_weight_grad_t, &
2636 atomic_grid_weight_grad_t, root_rank, print_components)
2637 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(INOUT) :: virial_xc
2639 REAL(kind=
dp),
INTENT(IN) :: exc
2641 atomic_grid_weight_grad_t
2642 LOGICAL,
INTENT(IN) :: root_rank
2643 LOGICAL,
INTENT(IN),
OPTIONAL :: print_components
2645 INTEGER :: feature_pos, i, idir, iw, j, k, &
2647 LOGICAL :: my_print_components
2648 REAL(kind=
dp) :: atomic_tmp, exc_tmp, grid_tmp, tmp
2649 REAL(kind=
dp),
DIMENSION(:),
POINTER :: atomic_grid_weight_grad, grid_weight_grad
2651 my_print_components = .false.
2652 IF (
PRESENT(print_components)) my_print_components = print_components
2654 NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
2656 CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
2663 DO k = lbound(features%feature_index, 3), ubound(features%feature_index, 3)
2664 DO j = lbound(features%feature_index, 2), ubound(features%feature_index, 2)
2665 DO i = lbound(features%feature_index, 1), ubound(features%feature_index, 1)
2666 local_row = local_row + 1
2667 DO feature_pos = features%local_feature_offsets(local_row), &
2668 features%local_feature_offsets(local_row + 1) - 1
2669 row = features%local_feature_rows(feature_pos)
2670 grid_tmp = grid_tmp + grid_weight_grad(row)*features%grid_weights(row)
2671 atomic_tmp = atomic_tmp + &
2672 atomic_grid_weight_grad(row)*features%atomic_grid_weights(row)
2677 cpassert(local_row == features%nflat_local)
2679 IF (root_rank) exc_tmp = -exc
2680 tmp = grid_tmp + atomic_tmp + exc_tmp
2682 IF (my_print_components .AND. root_rank)
THEN
2685 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight grid", grid_tmp
2686 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight atomic", atomic_tmp
2687 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight final", exc_tmp
2688 WRITE (iw,
"(T2,A,1X,ES20.10)")
"SKALA_GPW| XC virial weight residual", tmp
2693 virial_xc(idir, idir) = virial_xc(idir, idir) + tmp
2699 END SUBROUTINE build_weight_virial
2714 density_grad, grad_grad, kin_grad, &
2715 xc_deriv_method_id, global_grid_layout)
2716 TYPE(
pw_r3d_rs_type),
DIMENSION(:),
POINTER :: vxc_rho, vxc_tau, rho_r
2718 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: density_grad
2719 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: grad_grad
2720 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: kin_grad
2721 INTEGER,
INTENT(IN) :: xc_deriv_method_id
2722 LOGICAL,
INTENT(IN),
OPTIONAL :: global_grid_layout
2724 INTEGER :: i, ipt, ispin, j, k, nspins
2725 INTEGER,
DIMENSION(2, 3) :: bo
2726 LOGICAL :: my_global_grid_layout, valid_spin_shape
2727 REAL(kind=
dp) :: dvol_inv
2731 nspins =
SIZE(rho_r)
2732 bo = rho_r(1)%pw_grid%bounds_local
2733 dvol_inv = 1.0_dp/rho_r(1)%pw_grid%dvol
2734 my_global_grid_layout = .false.
2735 IF (
PRESENT(global_grid_layout)) my_global_grid_layout = global_grid_layout
2736 IF (my_global_grid_layout)
THEN
2737 cpassert(
SIZE(density_grad, 1) == product(rho_r(1)%pw_grid%npts))
2739 cpassert(
SIZE(kin_grad, 2) ==
SIZE(density_grad, 2))
2740 cpassert(
SIZE(grad_grad, 3) ==
SIZE(density_grad, 2))
2741 cpassert(
SIZE(grad_grad, 2) == 3)
2742 valid_spin_shape =
SIZE(density_grad, 2) == nspins .OR. &
2743 (nspins == 1 .AND.
SIZE(density_grad, 2) == 2)
2744 cpassert(valid_spin_shape)
2746 ALLOCATE (vxc_rho(nspins), vxc_tau(nspins))
2747 DO ispin = 1, nspins
2748 CALL pw_pool%create_pw(vxc_rho(ispin))
2749 CALL pw_pool%create_pw(vxc_tau(ispin))
2755 CALL pw_pool%create_pw(vxc_g)
2756 IF (.NOT. rho_r(1)%pw_grid%spherical)
CALL pw_pool%create_pw(tmp_g)
2759 DO ispin = 1, nspins
2761 CALL pw_pool%create_pw(grad_pw(i))
2766 DO k = bo(1, 3), bo(2, 3)
2767 DO j = bo(1, 2), bo(2, 2)
2768 DO i = bo(1, 1), bo(2, 1)
2769 IF (my_global_grid_layout)
THEN
2770 ipt = 1 + i - rho_r(1)%pw_grid%bounds(1, 1) + &
2771 rho_r(1)%pw_grid%npts(1)*( &
2772 j - rho_r(1)%pw_grid%bounds(1, 2) + &
2773 rho_r(1)%pw_grid%npts(2)*( &
2774 k - rho_r(1)%pw_grid%bounds(1, 3)))
2778 IF (nspins == 1)
THEN
2779 IF (
SIZE(density_grad, 2) == 1)
THEN
2780 vxc_rho(1)%array(i, j, k) = 0.5_dp*dvol_inv*density_grad(ipt, 1)
2781 vxc_tau(1)%array(i, j, k) = 0.5_dp*dvol_inv*kin_grad(ipt, 1)
2782 grad_pw(1)%array(i, j, k) = 0.5_dp*dvol_inv*grad_grad(ipt, 1, 1)
2783 grad_pw(2)%array(i, j, k) = 0.5_dp*dvol_inv*grad_grad(ipt, 2, 1)
2784 grad_pw(3)%array(i, j, k) = 0.5_dp*dvol_inv*grad_grad(ipt, 3, 1)
2786 vxc_rho(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2787 (density_grad(ipt, 1) + density_grad(ipt, 2))
2788 vxc_tau(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2789 (kin_grad(ipt, 1) + kin_grad(ipt, 2))
2790 grad_pw(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2791 (grad_grad(ipt, 1, 1) + grad_grad(ipt, 1, 2))
2792 grad_pw(2)%array(i, j, k) = 0.5_dp*dvol_inv* &
2793 (grad_grad(ipt, 2, 1) + grad_grad(ipt, 2, 2))
2794 grad_pw(3)%array(i, j, k) = 0.5_dp*dvol_inv* &
2795 (grad_grad(ipt, 3, 1) + grad_grad(ipt, 3, 2))
2798 vxc_rho(ispin)%array(i, j, k) = dvol_inv*density_grad(ipt, ispin)
2799 vxc_tau(ispin)%array(i, j, k) = dvol_inv*kin_grad(ipt, ispin)
2800 grad_pw(1)%array(i, j, k) = dvol_inv*grad_grad(ipt, 1, ispin)
2801 grad_pw(2)%array(i, j, k) = dvol_inv*grad_grad(ipt, 2, ispin)
2802 grad_pw(3)%array(i, j, k) = dvol_inv*grad_grad(ipt, 3, ispin)
2811 CALL xc_pw_divergence(xc_deriv_method_id, grad_pw, tmp_g, vxc_g, vxc_rho(ispin))
2814 CALL pw_pool%give_back_pw(grad_pw(i))
2818 IF (
ASSOCIATED(vxc_g%pw_grid))
CALL pw_pool%give_back_pw(vxc_g)
2819 IF (
ASSOCIATED(tmp_g%pw_grid))
CALL pw_pool%give_back_pw(tmp_g)
2828 SUBROUTINE print_native_grid_diagnostics(features, print_active)
2830 LOGICAL,
INTENT(IN) :: print_active
2832 INTEGER :: atom_rows_max, atom_rows_min, &
2833 chunk_rows_max, chunk_rows_min, iw
2834 REAL(kind=
dp) :: chunk_imbalance
2836 IF (.NOT. print_active)
RETURN
2840 WRITE (unit=iw, fmt=
"(/,T2,A,1X,ES19.11)") &
2841 "SKALA_GPW| Native grid feature electrons", features%electron_count
2842 WRITE (unit=iw, fmt=
"(T2,A,1X,ES19.11)") &
2843 "SKALA_GPW| Native grid feature spin moment", features%spin_moment
2844 WRITE (unit=iw, fmt=
"(T2,A,1X,ES19.11)") &
2845 "SKALA_GPW| Native grid feature kinetic integral", features%kinetic_integral
2846 WRITE (unit=iw, fmt=
"(T2,A,1X,ES19.11)") &
2847 "SKALA_GPW| Native grid feature weight sum", features%grid_weight_sum
2848 IF (
ALLOCATED(features%atomic_grid_sizes))
THEN
2849 atom_rows_min = int(minval(features%atomic_grid_sizes))
2850 atom_rows_max = int(maxval(features%atomic_grid_sizes))
2851 WRITE (unit=iw, fmt=
"(T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,I0)") &
2852 "SKALA_GPW| Native grid atom row range", atom_rows_min,
"to", &
2853 atom_rows_max,
"sum", int(sum(features%atomic_grid_sizes))
2855 IF (features%uses_atom_chunks)
THEN
2856 WRITE (unit=iw, fmt=
"(T2,A,1X,I0,1X,A,1X,I0)") &
2857 "SKALA_GPW| Native grid atom chunk rows", features%chunk_feature_count, &
2858 "of", features%nflat
2859 IF (
ALLOCATED(features%chunk_grad_counts))
THEN
2860 chunk_rows_min = minval(features%chunk_grad_counts)/ngrad_per_point
2861 chunk_rows_max = maxval(features%chunk_grad_counts)/ngrad_per_point
2862 chunk_imbalance = real(chunk_rows_max, kind=
dp)/real(max(1, chunk_rows_min), kind=
dp)
2863 WRITE (unit=iw, fmt=
"(T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,ES12.5)") &
2864 "SKALA_GPW| Native grid atom chunk row range", chunk_rows_min, &
2865 "to", chunk_rows_max,
"imbalance", chunk_imbalance
2869 END SUBROUTINE print_native_grid_diagnostics
2878 FUNCTION configure_native_grid_cuda(use_cuda, requested_device, group)
RESULT(selected_device)
2879 LOGICAL,
INTENT(IN) :: use_cuda
2880 INTEGER,
INTENT(IN) :: requested_device
2884 INTEGER :: cuda_device_count, iw, pe, selected_device
2885 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: selected_devices
2887 selected_device = -1
2889 IF (.NOT. use_cuda)
RETURN
2892 cuda_device_count = 0
2896 IF (cuda_device_count > 0)
THEN
2897 IF (requested_device < 0)
THEN
2898 selected_device = mod(group%mepos, cuda_device_count)
2900 selected_device = requested_device
2903 IF (selected_device >= cuda_device_count)
THEN
2904 CALL cp_abort(__location__, &
2905 "GAUXC%NATIVE_GRID_CUDA_DEVICE selects a CUDA device outside the visible "// &
2906 "Torch CUDA device range.")
2910 ALLOCATE (selected_devices(group%num_pe))
2911 CALL group%allgather(selected_device, selected_devices)
2913 IF (group%mepos /= 0)
THEN
2914 DEALLOCATE (selected_devices)
2917 IF (selected_device == logged_cuda_device .AND. &
2918 cuda_device_count == logged_cuda_device_count .AND. &
2919 group%num_pe == logged_cuda_nproc .AND. &
2920 requested_device == logged_cuda_request)
THEN
2921 DEALLOCATE (selected_devices)
2927 DEALLOCATE (selected_devices)
2930 IF (selected_device >= 0)
THEN
2931 WRITE (unit=iw, fmt=
"(/,T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,I0)") &
2932 "SKALA_GPW| Native grid Torch CUDA device", selected_device, &
2933 "of", cuda_device_count,
"requested", requested_device
2935 WRITE (unit=iw, fmt=
"(/,T2,A)") &
2936 "SKALA_GPW| Native grid Torch CUDA requested, but no Torch CUDA device is visible"
2938 WRITE (unit=iw, fmt=
"(T2,A)", advance=
"NO") &
2939 "SKALA_GPW| Native grid Torch CUDA rank devices"
2940 DO pe = 1, group%num_pe
2941 WRITE (unit=iw, fmt=
"(1X,I0,A,I0)", advance=
"NO") pe - 1,
":", selected_devices(pe)
2943 WRITE (unit=iw, fmt=*)
2945 logged_cuda_device = selected_device
2946 logged_cuda_device_count = cuda_device_count
2947 logged_cuda_nproc = group%num_pe
2948 logged_cuda_request = requested_device
2949 DEALLOCATE (selected_devices)
2951 END FUNCTION configure_native_grid_cuda
2958 SUBROUTINE ensure_model_loaded(model_path, cuda_device)
2959 CHARACTER(len=*),
INTENT(IN) :: model_path
2960 INTEGER,
INTENT(IN) :: cuda_device
2962 IF (cached_model_loaded)
THEN
2963 IF (trim(cached_model_path) == trim(model_path) .AND. &
2964 cached_model_cuda_device == cuda_device)
RETURN
2966 cached_model_loaded = .false.
2970 cached_model_path = model_path
2971 cached_model_cuda_device = cuda_device
2972 cached_model_loaded = .true.
2974 END SUBROUTINE ensure_model_loaded
2981 SUBROUTINE get_skala_model_path(xc_section, model_path)
2983 CHARACTER(len=default_path_length),
INTENT(OUT) :: model_path
2985 CHARACTER(len=default_path_length) :: model_key
2986 INTEGER :: env_status
2987 LOGICAL :: native_grid_use_cuda
2991 IF (.NOT.
ASSOCIATED(gauxc_section))
THEN
2992 cpabort(
"Native SKALA GPW requires an XC_FUNCTIONAL%GAUXC section")
2996 model_key = adjustl(model_path)
2998 IF (trim(model_key) ==
"NONE" .OR. trim(model_key) ==
"")
THEN
2999 cpabort(
"Native SKALA GPW requires GAUXC%MODEL SKALA or a TorchScript model path")
3000 ELSE IF (trim(model_key) ==
"SKALA")
THEN
3002 IF (native_grid_use_cuda)
THEN
3003 CALL get_environment_variable(
"GAUXC_SKALA_CUDA_MODEL", model_path, status=env_status)
3004 IF (env_status == 0 .AND. len_trim(model_path) > 0)
RETURN
3006 CALL get_environment_variable(
"GAUXC_SKALA_MODEL", model_path, status=env_status)
3007 IF (env_status /= 0 .OR. len_trim(model_path) == 0)
THEN
3008 IF (native_grid_use_cuda)
THEN
3009 CALL cp_abort(__location__, &
3010 "MODEL SKALA CUDA path requires GAUXC_SKALA_CUDA_MODEL or GAUXC_SKALA_MODEL")
3012 CALL cp_abort(__location__, &
3013 "MODEL SKALA requires the GAUXC_SKALA_MODEL environment variable")
3018 END SUBROUTINE get_skala_model_path
3032 NULLIFY (gauxc_section)
3033 IF (.NOT.
ASSOCIATED(xc_section))
RETURN
3036 IF (.NOT.
ASSOCIATED(functionals))
RETURN
3042 IF (.NOT.
ASSOCIATED(xc_fun))
EXIT
3043 IF (xc_fun%section%name ==
"GAUXC")
THEN
3044 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_get_exc(model, inputs, grid_weights, exc_tensor, exc)
Evaluate the weighted SKALA exchange-correlation energy.
subroutine, public skala_torch_model_load(model, filename)
Load a SKALA TorchScript model and its feature metadata.
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