Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Experimental CP2K-native GPW real-space-grid path for SKALA TorchScript models.
10 : ! **************************************************************************************************
11 : MODULE skala_gpw_functional
12 : USE cell_types, ONLY: cell_type,&
13 : pbc
14 : USE cp_array_utils, ONLY: cp_3d_r_cp_type
15 : USE cp_log_handling, ONLY: cp_logger_get_default_io_unit
16 : USE input_section_types, ONLY: section_get_rval,&
17 : section_vals_get_subs_vals,&
18 : section_vals_get_subs_vals2,&
19 : section_vals_type,&
20 : section_vals_val_get
21 : USE kinds, ONLY: default_path_length,&
22 : dp,&
23 : int_8
24 : USE message_passing, ONLY: mp_comm_type
25 : USE offload_api, ONLY: offload_set_chosen_device
26 : USE particle_types, ONLY: particle_type
27 : USE pw_grid_types, ONLY: pw_grid_type
28 : USE pw_methods, ONLY: pw_scale,&
29 : pw_zero
30 : USE pw_pool_types, ONLY: pw_pool_type
31 : USE pw_types, ONLY: pw_c1d_gs_type,&
32 : pw_r3d_rs_type
33 : USE qs_grid_atom, ONLY: grid_atom_type
34 : USE skala_gpw_features, ONLY: &
35 : skala_gpw_atom_partition_hard, skala_gpw_atom_partition_smooth, &
36 : skala_gpw_atom_subchunk_count, skala_gpw_atom_subchunk_layout, skala_gpw_feature_build, &
37 : skala_gpw_feature_build_atom_subchunk_bounds, skala_gpw_feature_release, &
38 : skala_gpw_feature_type, skala_gpw_smooth_partition_derivatives, &
39 : smooth_partition_atomic_weight_scale_derivative
40 : USE skala_torch_api, ONLY: skala_torch_model_get_exc,&
41 : skala_torch_model_load,&
42 : skala_torch_model_release,&
43 : skala_torch_model_type
44 : USE string_utilities, ONLY: uppercase
45 : USE torch_api, ONLY: &
46 : torch_cuda_device_count, torch_cuda_is_available, torch_dict_create, torch_dict_insert, &
47 : torch_dict_release, torch_dict_type, torch_tensor_backward_scalar, torch_tensor_data_ptr, &
48 : torch_tensor_from_array, torch_tensor_grad, torch_tensor_grad_batch3, &
49 : torch_tensor_release, torch_tensor_reset_from_array, torch_tensor_to_device_leaf, &
50 : torch_tensor_type, torch_use_cuda
51 : USE xc_input_constants, ONLY: skala_gapw_cp2k_default,&
52 : skala_gapw_direct_valence,&
53 : skala_gapw_paw_one_center,&
54 : skala_gapw_paw_one_center_split
55 : USE xc_rho_cflags_types, ONLY: xc_rho_cflags_type
56 : USE xc_rho_set_types, ONLY: xc_rho_set_create,&
57 : xc_rho_set_get,&
58 : xc_rho_set_release,&
59 : xc_rho_set_type,&
60 : xc_rho_set_update
61 : USE xc_util, ONLY: xc_pw_divergence,&
62 : xc_requires_tmp_g
63 : #include "./base/base_uses.f90"
64 :
65 : IMPLICIT NONE
66 :
67 : PRIVATE
68 :
69 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'skala_gpw_functional'
70 : INTEGER, PARAMETER, PRIVATE :: atom_chunk_auto_max_rows = 400000, &
71 : atom_chunk_auto_min_rows = 100000, &
72 : atom_chunk_auto_row_quantum = 100000, &
73 : ncollapsed_grad_per_point = 5, ngrad_per_point = 10
74 : INTEGER, PARAMETER, PUBLIC :: skala_gapw_density_partition_hard_minus_soft = 1, &
75 : skala_gapw_density_partition_hard_only = 2, &
76 : skala_gapw_density_partition_soft_only = 3, &
77 : skala_gapw_density_partition_none = 4
78 :
79 : TYPE skala_gapw_atom_cuda_tensor_cache_type
80 : TYPE(torch_tensor_type) :: atomic_coords_t, atomic_grid_weights_t, &
81 : density_t, grad_t, grid_coords_t, &
82 : grid_weights_t, kin_t
83 : END TYPE skala_gapw_atom_cuda_tensor_cache_type
84 :
85 : PUBLIC :: build_vxc_from_feature_grads, ensure_native_skala_grid_scope, get_gauxc_section, &
86 : skala_gapw_atom_composite_energy, skala_gapw_atom_vxc_of_r, &
87 : native_skala_gapw_atom_composite_requested, &
88 : native_skala_gapw_composite_direct_ao, native_skala_gapw_composite_reference, &
89 : native_skala_gapw_density_partition, skala_gpw_eval, skala_gpw_weight_derivative, &
90 : skala_gapw_representation, xc_section_uses_native_skala_evaluator, &
91 : xc_section_uses_native_skala_grid, xc_section_uses_gauxc_model
92 :
93 : TYPE(skala_torch_model_type), SAVE :: cached_model
94 : TYPE(skala_gapw_atom_cuda_tensor_cache_type), SAVE, TARGET :: cached_atom_cuda_tensors
95 : CHARACTER(len=default_path_length), SAVE :: cached_model_path = ""
96 : LOGICAL, SAVE :: cached_model_loaded = .FALSE.
97 : INTEGER, SAVE :: cached_model_cuda_device = -3
98 : INTEGER, SAVE :: logged_cuda_device = -3, &
99 : logged_cuda_device_count = -1, &
100 : logged_cuda_nproc = -1, &
101 : logged_cuda_request = -3
102 :
103 : CONTAINS
104 :
105 : ! **************************************************************************************************
106 : !> \brief Return true if the GAUXC subsection requests the CP2K-native GPW grid path.
107 : !> \param xc_section ...
108 : !> \return ...
109 : ! **************************************************************************************************
110 283012 : FUNCTION xc_section_uses_native_skala_grid(xc_section) RESULT(uses_native_grid)
111 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
112 : LOGICAL :: uses_native_grid
113 :
114 : TYPE(section_vals_type), POINTER :: gauxc_section
115 :
116 283012 : uses_native_grid = .FALSE.
117 283012 : gauxc_section => get_gauxc_section(xc_section)
118 283012 : IF (ASSOCIATED(gauxc_section)) THEN
119 1240 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID", l_val=uses_native_grid)
120 : END IF
121 :
122 283012 : END FUNCTION xc_section_uses_native_skala_grid
123 :
124 : ! **************************************************************************************************
125 : !> \brief Return the pseudopotential GAPW representation selected for an active model.
126 : !> \param xc_section ...
127 : !> \return ...
128 : ! **************************************************************************************************
129 188659 : FUNCTION skala_gapw_representation(xc_section) RESULT(representation)
130 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
131 : INTEGER :: representation
132 :
133 : TYPE(section_vals_type), POINTER :: gauxc_section
134 :
135 : representation = skala_gapw_cp2k_default
136 188183 : IF (.NOT. xc_section_uses_gauxc_model(xc_section)) RETURN
137 :
138 476 : gauxc_section => get_gauxc_section(xc_section)
139 476 : CPASSERT(ASSOCIATED(gauxc_section))
140 : CALL section_vals_val_get(gauxc_section, "PSEUDOPOTENTIAL_GAPW_REPRESENTATION", &
141 476 : i_val=representation)
142 :
143 : SELECT CASE (representation)
144 : CASE (skala_gapw_direct_valence, skala_gapw_paw_one_center, &
145 : skala_gapw_cp2k_default, skala_gapw_paw_one_center_split)
146 0 : CONTINUE
147 : CASE DEFAULT
148 476 : CALL cp_abort(__LOCATION__, "Unknown pseudopotential GAPW representation.")
149 : END SELECT
150 :
151 : END FUNCTION skala_gapw_representation
152 :
153 : ! **************************************************************************************************
154 : !> \brief Return true when SKALA must be evaluated by the CP2K-native grid machinery.
155 : !> \param xc_section ...
156 : !> \return ...
157 : ! **************************************************************************************************
158 158069 : FUNCTION xc_section_uses_native_skala_evaluator(xc_section) RESULT(uses_native_evaluator)
159 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
160 : LOGICAL :: uses_native_evaluator
161 :
162 : uses_native_evaluator = xc_section_uses_native_skala_grid(xc_section) .OR. &
163 : skala_gapw_representation(xc_section) == &
164 158069 : skala_gapw_paw_one_center
165 :
166 158069 : END FUNCTION xc_section_uses_native_skala_evaluator
167 :
168 : ! **************************************************************************************************
169 : !> \brief Return true if native SKALA should use the full GAPW ORB density on one common grid.
170 : !> \param xc_section ...
171 : !> \return ...
172 : ! **************************************************************************************************
173 145335 : FUNCTION native_skala_gapw_composite_reference(xc_section) RESULT(use_composite_reference)
174 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
175 : LOGICAL :: use_composite_reference
176 :
177 : LOGICAL :: native_grid
178 : TYPE(section_vals_type), POINTER :: gauxc_section
179 :
180 145335 : use_composite_reference = .FALSE.
181 145335 : native_grid = .FALSE.
182 145335 : gauxc_section => get_gauxc_section(xc_section)
183 145335 : IF (ASSOCIATED(gauxc_section)) THEN
184 1884 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID", l_val=native_grid)
185 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_GAPW_COMPOSITE_REFERENCE", &
186 1884 : l_val=use_composite_reference)
187 : END IF
188 145335 : use_composite_reference = native_grid .AND. use_composite_reference
189 :
190 145335 : END FUNCTION native_skala_gapw_composite_reference
191 :
192 : ! **************************************************************************************************
193 : !> \brief Return true when the explicit atom-centered composite reference is requested.
194 : !> \param xc_section ...
195 : !> \return ...
196 : ! **************************************************************************************************
197 1840 : FUNCTION native_skala_gapw_atom_composite_requested(xc_section) RESULT(use_atom_composite)
198 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
199 : LOGICAL :: use_atom_composite
200 :
201 : LOGICAL :: native_grid
202 : TYPE(section_vals_type), POINTER :: gauxc_section
203 :
204 1840 : use_atom_composite = .FALSE.
205 1840 : native_grid = .FALSE.
206 1840 : gauxc_section => get_gauxc_section(xc_section)
207 1840 : IF (ASSOCIATED(gauxc_section)) THEN
208 372 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID", l_val=native_grid)
209 : CALL section_vals_val_get(gauxc_section, &
210 : "NATIVE_GRID_GAPW_ATOM_COMPOSITE_REFERENCE", &
211 372 : l_val=use_atom_composite)
212 : END IF
213 1840 : use_atom_composite = native_grid .AND. use_atom_composite
214 :
215 1840 : END FUNCTION native_skala_gapw_atom_composite_requested
216 :
217 : ! **************************************************************************************************
218 : !> \brief Return true if the GAPW composite reference uses direct full-ORB collocation.
219 : !> \param xc_section ...
220 : !> \return ...
221 : ! **************************************************************************************************
222 192 : FUNCTION native_skala_gapw_composite_direct_ao(xc_section) RESULT(use_direct_ao)
223 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
224 : LOGICAL :: use_direct_ao
225 :
226 : TYPE(section_vals_type), POINTER :: gauxc_section
227 :
228 192 : use_direct_ao = .FALSE.
229 192 : gauxc_section => get_gauxc_section(xc_section)
230 192 : IF (ASSOCIATED(gauxc_section)) THEN
231 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_GAPW_COMPOSITE_DIRECT_AO", &
232 192 : l_val=use_direct_ao)
233 : END IF
234 192 : use_direct_ao = native_skala_gapw_composite_reference(xc_section) .AND. use_direct_ao
235 :
236 192 : END FUNCTION native_skala_gapw_composite_direct_ao
237 :
238 : ! **************************************************************************************************
239 : !> \brief Return true if the GAUXC subsection requests a model evaluation.
240 : !> \param xc_section ...
241 : !> \return ...
242 : ! **************************************************************************************************
243 220239 : FUNCTION xc_section_uses_gauxc_model(xc_section) RESULT(uses_gauxc_model)
244 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
245 : LOGICAL :: uses_gauxc_model
246 :
247 : CHARACTER(len=default_path_length) :: model_key, model_name, xc_key, xc_name
248 : TYPE(section_vals_type), POINTER :: gauxc_section
249 :
250 220239 : uses_gauxc_model = .FALSE.
251 220239 : gauxc_section => get_gauxc_section(xc_section)
252 220239 : IF (ASSOCIATED(gauxc_section)) THEN
253 690 : CALL section_vals_val_get(gauxc_section, "MODEL", c_val=model_name)
254 690 : CALL section_vals_val_get(gauxc_section, "FUNCTIONAL", c_val=xc_name)
255 690 : model_key = ADJUSTL(model_name)
256 690 : xc_key = ADJUSTL(xc_name)
257 690 : CALL uppercase(model_key)
258 690 : CALL uppercase(xc_key)
259 : uses_gauxc_model = (TRIM(model_key) /= "" .AND. TRIM(model_key) /= "NONE" .AND. &
260 690 : TRIM(model_key) /= TRIM(xc_key))
261 : END IF
262 :
263 220239 : END FUNCTION xc_section_uses_gauxc_model
264 :
265 : ! **************************************************************************************************
266 : !> \brief Return the hard/soft GAPW one-center density partition for native SKALA.
267 : !> \param xc_section ...
268 : !> \return ...
269 : ! **************************************************************************************************
270 82 : FUNCTION native_skala_gapw_density_partition(xc_section) RESULT(partition)
271 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
272 : INTEGER :: partition
273 :
274 : TYPE(section_vals_type), POINTER :: gauxc_section
275 :
276 82 : partition = skala_gapw_density_partition_hard_minus_soft
277 82 : gauxc_section => get_gauxc_section(xc_section)
278 82 : IF (ASSOCIATED(gauxc_section)) THEN
279 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_GAPW_DENSITY_PARTITION", &
280 82 : i_val=partition)
281 : END IF
282 :
283 : SELECT CASE (partition)
284 : CASE (skala_gapw_density_partition_hard_minus_soft, &
285 : skala_gapw_density_partition_hard_only, &
286 : skala_gapw_density_partition_soft_only, &
287 : skala_gapw_density_partition_none)
288 0 : CONTINUE
289 : CASE DEFAULT
290 : CALL cp_abort(__LOCATION__, &
291 82 : "Unknown GAUXC%NATIVE_GRID_GAPW_DENSITY_PARTITION value.")
292 : END SELECT
293 :
294 82 : END FUNCTION native_skala_gapw_density_partition
295 :
296 : ! **************************************************************************************************
297 : !> \brief Enforce the currently implemented native SKALA GPW input scope.
298 : !> \param xc_section ...
299 : ! **************************************************************************************************
300 652 : SUBROUTINE ensure_native_skala_grid_scope(xc_section)
301 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
302 :
303 : CHARACTER(len=default_path_length) :: model_key, model_name
304 : INTEGER :: ifun, nfun
305 : LOGICAL :: native_grid
306 : TYPE(section_vals_type), POINTER :: functionals, gauxc_section, xc_fun
307 :
308 326 : NULLIFY (gauxc_section)
309 326 : IF (.NOT. ASSOCIATED(xc_section)) THEN
310 0 : CPABORT("Native SKALA GPW requires an XC section")
311 : END IF
312 :
313 326 : functionals => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
314 326 : IF (.NOT. ASSOCIATED(functionals)) THEN
315 0 : CPABORT("Native SKALA GPW requires an XC_FUNCTIONAL section")
316 : END IF
317 :
318 326 : nfun = 0
319 326 : ifun = 0
320 : DO
321 652 : ifun = ifun + 1
322 652 : xc_fun => section_vals_get_subs_vals2(functionals, i_section=ifun)
323 652 : IF (.NOT. ASSOCIATED(xc_fun)) EXIT
324 326 : nfun = nfun + 1
325 652 : IF (xc_fun%section%name == "GAUXC") gauxc_section => xc_fun
326 : END DO
327 :
328 326 : IF (.NOT. ASSOCIATED(gauxc_section)) THEN
329 0 : CPABORT("Native SKALA GPW requires an XC_FUNCTIONAL%GAUXC section")
330 : END IF
331 326 : IF (nfun /= 1) THEN
332 0 : CPABORT("Native SKALA GPW requires GAUXC to be the only XC functional")
333 : END IF
334 :
335 326 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID", l_val=native_grid)
336 326 : IF (.NOT. native_grid .AND. &
337 0 : .NOT. xc_section_uses_native_skala_evaluator(xc_section)) RETURN
338 :
339 326 : CALL section_vals_val_get(gauxc_section, "MODEL", c_val=model_name)
340 326 : model_key = ADJUSTL(model_name)
341 326 : CALL uppercase(model_key)
342 326 : IF (TRIM(model_key) == "NONE" .OR. TRIM(model_key) == "") THEN
343 0 : CPABORT("Native SKALA GPW requires GAUXC%MODEL SKALA or a TorchScript model path")
344 : END IF
345 :
346 : END SUBROUTINE ensure_native_skala_grid_scope
347 :
348 : ! **************************************************************************************************
349 : !> \brief Evaluate SKALA energy and first derivatives on a CP2K GPW grid.
350 : !> \param vxc_rho ...
351 : !> \param vxc_tau ...
352 : !> \param exc ...
353 : !> \param rho_r ...
354 : !> \param rho_g ...
355 : !> \param tau ...
356 : !> \param xc_section ...
357 : !> \param weights ...
358 : !> \param pw_pool ...
359 : !> \param particle_set ...
360 : !> \param cell ...
361 : !> \param compute_virial ...
362 : !> \param virial_xc ...
363 : !> \param just_energy ...
364 : !> \param atom_force ...
365 : ! **************************************************************************************************
366 322 : SUBROUTINE skala_gpw_eval(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, &
367 : weights, pw_pool, particle_set, cell, compute_virial, virial_xc, &
368 322 : just_energy, atom_force)
369 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: vxc_rho, vxc_tau
370 : REAL(KIND=dp), INTENT(OUT) :: exc
371 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
372 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
373 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
374 : TYPE(section_vals_type), POINTER :: xc_section
375 : TYPE(pw_r3d_rs_type), POINTER :: weights
376 : TYPE(pw_pool_type), POINTER :: pw_pool
377 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
378 : TYPE(cell_type), POINTER :: cell
379 : LOGICAL, INTENT(IN) :: compute_virial
380 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT) :: virial_xc
381 : LOGICAL, INTENT(IN), OPTIONAL :: just_energy
382 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT), &
383 : OPTIONAL :: atom_force
384 :
385 : CHARACTER(len=default_path_length) :: model_path
386 : INTEGER :: i, ipt, ispin, iw, j, k, native_grid_atom_chunk_max_rows, &
387 : native_grid_atom_partition, native_grid_atom_subchunks, native_grid_cuda_device, nspins, &
388 : phase_handle, selected_cuda_device, xc_deriv_method_id, xc_rho_smooth_id
389 : INTEGER, DIMENSION(2, 3) :: bo
390 : LOGICAL :: has_atom_chunk_work, have_atom_coord_grad, lsd, my_just_energy, &
391 : native_grid_atom_chunk_routing, native_grid_atom_chunks, native_grid_diagnostics, &
392 : native_grid_use_cuda, needs_atom_force, use_atom_subchunks
393 : REAL(KIND=dp) :: density_contraction, tau_contraction
394 322 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: density_grad, kin_grad
395 322 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: grad_grad
396 : REAL(KIND=dp), DIMENSION(3, 3) :: virial_before
397 : TYPE(section_vals_type), POINTER :: gauxc_section
398 322 : TYPE(skala_gpw_feature_type) :: features
399 : TYPE(torch_tensor_type) :: atom_coord_grad_t, &
400 : atomic_grid_weight_grad_t, exc_tensor, &
401 : grid_coord_grad_t, grid_weight_grad_t
402 : TYPE(xc_rho_cflags_type) :: needs
403 : TYPE(xc_rho_set_type) :: rho_set
404 :
405 322 : virial_xc = 0.0_dp
406 322 : exc = 0.0_dp
407 322 : my_just_energy = .FALSE.
408 322 : IF (PRESENT(just_energy)) my_just_energy = just_energy
409 322 : needs_atom_force = PRESENT(atom_force)
410 834 : IF (needs_atom_force) atom_force = 0.0_dp
411 322 : have_atom_coord_grad = .FALSE.
412 :
413 322 : IF (compute_virial .AND. my_just_energy) THEN
414 : CALL cp_abort(__LOCATION__, &
415 0 : "Native SKALA GPW stress/virial requires feature gradients.")
416 : END IF
417 322 : IF (.NOT. ASSOCIATED(rho_g)) THEN
418 : CALL cp_abort(__LOCATION__, &
419 0 : "Native SKALA GPW requires the reciprocal-space density to form density gradients.")
420 : END IF
421 322 : IF (.NOT. ASSOCIATED(tau)) THEN
422 : CALL cp_abort(__LOCATION__, &
423 0 : "Native SKALA GPW requires the kinetic-energy density.")
424 : END IF
425 :
426 322 : nspins = SIZE(rho_r)
427 322 : lsd = (nspins /= 1)
428 322 : CALL get_skala_model_path(xc_section, model_path)
429 322 : gauxc_section => get_gauxc_section(xc_section)
430 322 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_USE_CUDA", l_val=native_grid_use_cuda)
431 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_CUDA_DEVICE", &
432 322 : i_val=native_grid_cuda_device)
433 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_ATOM_CHUNKS", &
434 322 : l_val=native_grid_atom_chunks)
435 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_ATOM_CHUNK_ROUTING", &
436 322 : l_val=native_grid_atom_chunk_routing)
437 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_ATOM_CHUNK_MAX_ROWS", &
438 322 : i_val=native_grid_atom_chunk_max_rows)
439 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_ATOM_PARTITION", &
440 322 : i_val=native_grid_atom_partition)
441 26 : SELECT CASE (native_grid_atom_partition)
442 : CASE (1)
443 26 : native_grid_atom_partition = skala_gpw_atom_partition_hard
444 : CASE (2)
445 296 : native_grid_atom_partition = skala_gpw_atom_partition_smooth
446 : CASE DEFAULT
447 : CALL cp_abort(__LOCATION__, &
448 322 : "Unknown GAUXC%NATIVE_GRID_ATOM_PARTITION value.")
449 : END SELECT
450 322 : native_grid_atom_chunk_routing = native_grid_atom_chunk_routing .OR. native_grid_atom_chunks
451 322 : native_grid_atom_chunks = native_grid_atom_chunks .OR. native_grid_atom_chunk_routing
452 322 : IF (native_grid_atom_chunk_max_rows < -1) THEN
453 : CALL cp_abort(__LOCATION__, &
454 0 : "GAUXC%NATIVE_GRID_ATOM_CHUNK_MAX_ROWS must be -1, zero, or positive.")
455 : END IF
456 322 : IF (needs_atom_force .OR. compute_virial) THEN
457 64 : IF (native_grid_atom_partition == skala_gpw_atom_partition_hard) THEN
458 0 : native_grid_atom_partition = skala_gpw_atom_partition_smooth
459 : END IF
460 64 : native_grid_atom_chunk_routing = .FALSE.
461 64 : native_grid_atom_chunks = .FALSE.
462 : END IF
463 : ! The portable SKALA export used by the regtests builds ragged-index tensors on CPU.
464 322 : CALL torch_use_cuda(native_grid_use_cuda)
465 : selected_cuda_device = configure_native_grid_cuda( &
466 322 : native_grid_use_cuda, native_grid_cuda_device, rho_r(1)%pw_grid%para%group)
467 322 : CALL ensure_model_loaded(model_path, selected_cuda_device)
468 :
469 322 : IF (lsd) THEN
470 48 : needs%rho_spin = .TRUE.
471 48 : needs%drho_spin = .TRUE.
472 48 : needs%tau_spin = .TRUE.
473 : ELSE
474 274 : needs%rho = .TRUE.
475 274 : needs%drho = .TRUE.
476 274 : needs%tau = .TRUE.
477 : END IF
478 :
479 322 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", i_val=xc_deriv_method_id)
480 322 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_SMOOTH_RHO", i_val=xc_rho_smooth_id)
481 :
482 : CALL xc_rho_set_create(rho_set, &
483 : rho_r(1)%pw_grid%bounds_local, &
484 : rho_cutoff=section_get_rval(xc_section, "density_cutoff"), &
485 : drho_cutoff=section_get_rval(xc_section, "gradient_cutoff"), &
486 322 : tau_cutoff=section_get_rval(xc_section, "tau_cutoff"))
487 : CALL xc_rho_set_update(rho_set, rho_r, rho_g, tau, needs, &
488 322 : xc_deriv_method_id, xc_rho_smooth_id, pw_pool)
489 :
490 : CALL skala_gpw_feature_build(features, rho_set, rho_r, particle_set, cell, &
491 : requires_grad=(.NOT. my_just_energy), weights=weights, &
492 : requires_coordinate_grad=(needs_atom_force .OR. compute_virial), &
493 : requires_stress_grad=compute_virial, &
494 : use_atom_chunks=native_grid_atom_chunks, &
495 : route_atom_chunks=native_grid_atom_chunk_routing, &
496 580 : atom_partition=native_grid_atom_partition)
497 322 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_DIAGNOSTICS", l_val=native_grid_diagnostics)
498 322 : IF (native_grid_diagnostics) THEN
499 58 : CALL print_native_grid_diagnostics(features, rho_r(1)%pw_grid%para%group%mepos == 0)
500 : END IF
501 :
502 322 : IF (features%uses_atom_chunks .AND. native_grid_atom_chunk_max_rows == -1) THEN
503 : native_grid_atom_chunk_max_rows = auto_atom_chunk_max_rows(features, &
504 250 : rho_r(1)%pw_grid%para%group)
505 : END IF
506 322 : IF (native_grid_diagnostics .AND. features%uses_atom_chunks .AND. &
507 : rho_r(1)%pw_grid%para%group%mepos == 0) THEN
508 27 : iw = cp_logger_get_default_io_unit()
509 27 : IF (iw > 0) THEN
510 : WRITE (UNIT=iw, FMT="(T2,A,1X,I0)") &
511 27 : "SKALA_GPW| Native grid atom chunk max rows", native_grid_atom_chunk_max_rows
512 : END IF
513 : END IF
514 322 : native_grid_atom_subchunks = 1
515 322 : IF (features%uses_atom_chunks .AND. native_grid_atom_chunk_max_rows > 0) THEN
516 258 : native_grid_atom_subchunks = skala_gpw_atom_subchunk_count(native_grid_atom_chunk_max_rows)
517 258 : CALL rho_r(1)%pw_grid%para%group%max(native_grid_atom_subchunks)
518 : END IF
519 322 : use_atom_subchunks = features%uses_atom_chunks .AND. native_grid_atom_subchunks > 1
520 322 : has_atom_chunk_work = .NOT. features%uses_atom_chunks .OR. features%chunk_feature_count > 0
521 322 : exc = 0.0_dp
522 322 : IF (use_atom_subchunks) THEN
523 : CALL evaluate_atom_subchunks(features, rho_r(1)%pw_grid%para%group, &
524 : native_grid_atom_chunk_max_rows, &
525 : compute_grads=(.NOT. my_just_energy), exc=exc, &
526 : density_grad=density_grad, grad_grad=grad_grad, &
527 2 : kin_grad=kin_grad, collapse_spin_grads=(nspins == 1))
528 320 : ELSE IF (has_atom_chunk_work) THEN
529 : CALL skala_torch_model_get_exc(cached_model, features%inputs, &
530 320 : features%grid_weights_t, exc_tensor, exc)
531 : END IF
532 322 : IF (features%uses_atom_chunks) CALL rho_r(1)%pw_grid%para%group%sum(exc)
533 :
534 322 : IF (.NOT. my_just_energy) THEN
535 298 : IF (.NOT. use_atom_subchunks) THEN
536 296 : IF (has_atom_chunk_work) THEN
537 296 : CALL timeset("skala_gpw_backward", phase_handle)
538 296 : CALL torch_tensor_backward_scalar(exc_tensor)
539 296 : CALL timestop(phase_handle)
540 :
541 296 : IF (compute_virial) THEN
542 54 : IF (native_grid_diagnostics) virial_before = virial_xc
543 : CALL build_weight_virial(virial_xc, features, exc, grid_weight_grad_t, &
544 : atomic_grid_weight_grad_t, &
545 : rho_r(1)%pw_grid%para%group%mepos == 0, &
546 54 : native_grid_diagnostics)
547 54 : IF (native_grid_diagnostics) THEN
548 : CALL print_virial_delta("weight-residual", virial_xc - virial_before, &
549 52 : rho_r(1)%pw_grid%para%group%mepos == 0)
550 : END IF
551 : END IF
552 : END IF
553 :
554 296 : CALL timeset("skala_gpw_grad_fetch", phase_handle)
555 296 : IF (features%uses_atom_chunks) THEN
556 : CALL fetch_and_gather_atom_chunk_grads(features, rho_r(1)%pw_grid%para%group, &
557 232 : density_grad, grad_grad, kin_grad)
558 : ELSE
559 64 : CALL fetch_local_feature_grads(features, density_grad, grad_grad, kin_grad)
560 : END IF
561 296 : CALL timestop(phase_handle)
562 : END IF
563 298 : IF (needs_atom_force) THEN
564 : CALL add_explicit_coordinate_force(atom_force, features, atom_coord_grad_t, &
565 64 : rho_r(1)%pw_grid%para%group%mepos == 0)
566 64 : IF (features%atom_partition == skala_gpw_atom_partition_smooth) THEN
567 : CALL add_smooth_partition_force(atom_force, features, particle_set, cell, rho_r, &
568 64 : grid_weight_grad_t, atomic_grid_weight_grad_t)
569 : END IF
570 : have_atom_coord_grad = .TRUE.
571 : END IF
572 :
573 298 : CALL timeset("skala_gpw_vxc_unpack", phase_handle)
574 298 : IF (native_grid_diagnostics) THEN
575 340 : bo = rho_r(1)%pw_grid%bounds_local
576 34 : density_contraction = 0.0_dp
577 34 : tau_contraction = 0.0_dp
578 34 : ipt = 0
579 1266 : DO k = bo(1, 3), bo(2, 3)
580 48914 : DO j = bo(1, 2), bo(2, 2)
581 1009796 : DO i = bo(1, 1), bo(2, 1)
582 960916 : ipt = ipt + 1
583 1008564 : IF (nspins == 1) THEN
584 : density_contraction = density_contraction + rho_r(1)%array(i, j, k)* &
585 687541 : 0.5_dp*(density_grad(ipt, 1) + density_grad(ipt, 2))
586 : tau_contraction = tau_contraction + tau(1)%array(i, j, k)* &
587 687541 : 0.5_dp*(kin_grad(ipt, 1) + kin_grad(ipt, 2))
588 : ELSE
589 820125 : DO ispin = 1, nspins
590 : density_contraction = density_contraction + &
591 546750 : rho_r(ispin)%array(i, j, k)*density_grad(ipt, ispin)
592 : tau_contraction = tau_contraction + &
593 820125 : tau(ispin)%array(i, j, k)*kin_grad(ipt, ispin)
594 : END DO
595 : END IF
596 : END DO
597 : END DO
598 : END DO
599 34 : CALL rho_r(1)%pw_grid%para%group%sum(density_contraction)
600 34 : CALL rho_r(1)%pw_grid%para%group%sum(tau_contraction)
601 34 : IF (rho_r(1)%pw_grid%para%group%mepos == 0) THEN
602 17 : iw = cp_logger_get_default_io_unit()
603 17 : IF (iw > 0) THEN
604 : WRITE (iw, "(T2,A,1X,ES20.10)") &
605 17 : "SKALA_GPW| XC density-gradient contraction", density_contraction
606 : WRITE (iw, "(T2,A,1X,ES20.10)") &
607 17 : "SKALA_GPW| XC kinetic-gradient contraction", tau_contraction
608 : END IF
609 : END IF
610 : END IF
611 298 : IF (compute_virial) THEN
612 54 : IF (native_grid_diagnostics) virial_before = virial_xc
613 54 : CALL build_virial_from_feature_grads(virial_xc, rho_set, rho_r, grad_grad)
614 54 : IF (native_grid_diagnostics) THEN
615 : CALL print_virial_delta("feature-gradient", virial_xc - virial_before, &
616 52 : rho_r(1)%pw_grid%para%group%mepos == 0)
617 4 : virial_before = virial_xc
618 : END IF
619 54 : IF (.NOT. have_atom_coord_grad) THEN
620 0 : CALL torch_tensor_grad(features%coarse_0_atomic_coords_t, atom_coord_grad_t)
621 0 : have_atom_coord_grad = .TRUE.
622 : END IF
623 : CALL build_static_coordinate_virial(virial_xc, features, atom_coord_grad_t, &
624 : grid_coord_grad_t, &
625 : rho_r(1)%pw_grid%para%group%mepos == 0, &
626 54 : native_grid_diagnostics)
627 54 : IF (native_grid_diagnostics) THEN
628 : CALL print_virial_delta("static-coordinates", virial_xc - virial_before, &
629 52 : rho_r(1)%pw_grid%para%group%mepos == 0)
630 4 : virial_before = virial_xc
631 : END IF
632 54 : IF (features%atom_partition == skala_gpw_atom_partition_smooth) THEN
633 : CALL build_smooth_partition_virial(virial_xc, features, particle_set, cell, rho_r, &
634 54 : grid_weight_grad_t, atomic_grid_weight_grad_t)
635 54 : IF (native_grid_diagnostics) THEN
636 : CALL print_virial_delta("smooth-partition", virial_xc - virial_before, &
637 52 : rho_r(1)%pw_grid%para%group%mepos == 0)
638 : virial_before = virial_xc
639 : END IF
640 : END IF
641 : END IF
642 : CALL build_vxc_from_feature_grads(vxc_rho, vxc_tau, rho_r, pw_pool, &
643 : density_grad, grad_grad, kin_grad, &
644 298 : xc_deriv_method_id)
645 298 : CALL timestop(phase_handle)
646 :
647 298 : CALL timeset("skala_gpw_grad_release", phase_handle)
648 298 : DEALLOCATE (density_grad, grad_grad, kin_grad)
649 298 : IF (have_atom_coord_grad) CALL torch_tensor_release(atom_coord_grad_t)
650 298 : CALL timestop(phase_handle)
651 : END IF
652 :
653 322 : CALL timeset("skala_gpw_cleanup", phase_handle)
654 322 : IF (.NOT. use_atom_subchunks .AND. has_atom_chunk_work) CALL torch_tensor_release(exc_tensor)
655 322 : CALL skala_gpw_feature_release(features)
656 322 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
657 322 : CALL torch_use_cuda(.TRUE.)
658 322 : CALL timestop(phase_handle)
659 :
660 6440 : END SUBROUTINE skala_gpw_eval
661 :
662 : ! **************************************************************************************************
663 : !> \brief Evaluate the derivative of native SKALA XC energy with respect to CP2K's external
664 : !> real-space integration-weight multiplier.
665 : !> \param weight_deriv_r ...
666 : !> \param rho_r ...
667 : !> \param rho_g ...
668 : !> \param tau ...
669 : !> \param xc_section ...
670 : !> \param weights ...
671 : !> \param pw_pool ...
672 : !> \param particle_set ...
673 : !> \param cell ...
674 : ! **************************************************************************************************
675 0 : SUBROUTINE skala_gpw_weight_derivative(weight_deriv_r, rho_r, rho_g, tau, xc_section, &
676 : weights, pw_pool, particle_set, cell)
677 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: weight_deriv_r
678 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
679 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
680 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
681 : TYPE(section_vals_type), POINTER :: xc_section
682 : TYPE(pw_r3d_rs_type), POINTER :: weights
683 : TYPE(pw_pool_type), POINTER :: pw_pool
684 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
685 : TYPE(cell_type), POINTER :: cell
686 :
687 : CHARACTER(len=default_path_length) :: model_path
688 : INTEGER :: feature_begin, feature_end, feature_pos, i, iatom, j, k, local_row, &
689 : native_grid_atom_partition, native_grid_cuda_device, natom, nspins, row, &
690 : selected_cuda_device, xc_deriv_method_id, xc_rho_smooth_id
691 : INTEGER, DIMENSION(2, 3) :: bo
692 : LOGICAL :: lsd, native_grid_use_cuda
693 0 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: included
694 : REAL(KIND=dp) :: exc, local_derivative
695 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: partition_weights
696 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: atom_coords_pbc
697 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
698 : REAL(KIND=dp), DIMENSION(3) :: grid_point
699 0 : REAL(KIND=dp), DIMENSION(:), POINTER :: grid_weight_grad
700 : TYPE(section_vals_type), POINTER :: gauxc_section
701 0 : TYPE(skala_gpw_feature_type) :: features
702 : TYPE(torch_tensor_type) :: exc_tensor, grid_weight_grad_t
703 : TYPE(xc_rho_cflags_type) :: needs
704 : TYPE(xc_rho_set_type) :: rho_set
705 :
706 0 : CPASSERT(ASSOCIATED(rho_r))
707 0 : CPASSERT(ASSOCIATED(rho_g))
708 0 : CPASSERT(ASSOCIATED(tau))
709 0 : CALL pw_zero(weight_deriv_r)
710 :
711 0 : nspins = SIZE(rho_r)
712 0 : lsd = (nspins /= 1)
713 0 : CALL get_skala_model_path(xc_section, model_path)
714 0 : gauxc_section => get_gauxc_section(xc_section)
715 0 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_USE_CUDA", l_val=native_grid_use_cuda)
716 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_CUDA_DEVICE", &
717 0 : i_val=native_grid_cuda_device)
718 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_ATOM_PARTITION", &
719 0 : i_val=native_grid_atom_partition)
720 0 : SELECT CASE (native_grid_atom_partition)
721 : CASE (1)
722 0 : native_grid_atom_partition = skala_gpw_atom_partition_hard
723 : CASE (2)
724 0 : native_grid_atom_partition = skala_gpw_atom_partition_smooth
725 : CASE DEFAULT
726 : CALL cp_abort(__LOCATION__, &
727 0 : "Unknown GAUXC%NATIVE_GRID_ATOM_PARTITION value.")
728 : END SELECT
729 0 : IF (native_grid_atom_partition == skala_gpw_atom_partition_hard) THEN
730 0 : native_grid_atom_partition = skala_gpw_atom_partition_smooth
731 : END IF
732 :
733 0 : CALL torch_use_cuda(native_grid_use_cuda)
734 : selected_cuda_device = configure_native_grid_cuda( &
735 0 : native_grid_use_cuda, native_grid_cuda_device, rho_r(1)%pw_grid%para%group)
736 0 : CALL ensure_model_loaded(model_path, selected_cuda_device)
737 :
738 0 : IF (lsd) THEN
739 0 : needs%rho_spin = .TRUE.
740 0 : needs%drho_spin = .TRUE.
741 0 : needs%tau_spin = .TRUE.
742 : ELSE
743 0 : needs%rho = .TRUE.
744 0 : needs%drho = .TRUE.
745 0 : needs%tau = .TRUE.
746 : END IF
747 :
748 0 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", i_val=xc_deriv_method_id)
749 0 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_SMOOTH_RHO", i_val=xc_rho_smooth_id)
750 :
751 : CALL xc_rho_set_create(rho_set, &
752 : rho_r(1)%pw_grid%bounds_local, &
753 : rho_cutoff=section_get_rval(xc_section, "density_cutoff"), &
754 : drho_cutoff=section_get_rval(xc_section, "gradient_cutoff"), &
755 0 : tau_cutoff=section_get_rval(xc_section, "tau_cutoff"))
756 : CALL xc_rho_set_update(rho_set, rho_r, rho_g, tau, needs, &
757 0 : xc_deriv_method_id, xc_rho_smooth_id, pw_pool)
758 :
759 : CALL skala_gpw_feature_build(features, rho_set, rho_r, particle_set, cell, &
760 : requires_grad=.FALSE., weights=weights, &
761 : requires_coordinate_grad=.FALSE., &
762 : requires_stress_grad=.TRUE., &
763 : use_atom_chunks=.FALSE., route_atom_chunks=.FALSE., &
764 0 : atom_partition=native_grid_atom_partition)
765 : CALL skala_torch_model_get_exc(cached_model, features%inputs, features%grid_weights_t, &
766 0 : exc_tensor, exc)
767 0 : CALL torch_tensor_backward_scalar(exc_tensor)
768 0 : NULLIFY (grid_weight_grad)
769 0 : CALL torch_tensor_grad(features%grid_weights_t, grid_weight_grad_t)
770 0 : CALL torch_tensor_data_ptr(grid_weight_grad_t, grid_weight_grad)
771 :
772 0 : natom = SIZE(particle_set)
773 0 : IF (native_grid_atom_partition == skala_gpw_atom_partition_smooth) THEN
774 : ALLOCATE (atom_coords_pbc(3, natom), included(natom), partition_weights(natom), &
775 0 : dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
776 0 : DO iatom = 1, natom
777 0 : atom_coords_pbc(:, iatom) = pbc(particle_set(iatom)%r, cell, positive_range=.TRUE.)
778 : END DO
779 : END IF
780 :
781 0 : bo = rho_r(1)%pw_grid%bounds_local
782 0 : local_row = 0
783 0 : DO k = bo(1, 3), bo(2, 3)
784 0 : DO j = bo(1, 2), bo(2, 2)
785 0 : DO i = bo(1, 1), bo(2, 1)
786 0 : local_row = local_row + 1
787 0 : feature_begin = features%local_feature_offsets(local_row)
788 0 : feature_end = features%local_feature_offsets(local_row + 1) - 1
789 0 : local_derivative = 0.0_dp
790 0 : IF (native_grid_atom_partition == skala_gpw_atom_partition_hard) THEN
791 0 : CPASSERT(feature_end == feature_begin)
792 0 : row = features%local_feature_rows(feature_begin)
793 0 : local_derivative = grid_weight_grad(row)
794 : ELSE
795 0 : grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
796 : CALL skala_gpw_smooth_partition_derivatives( &
797 : grid_point, atom_coords_pbc, cell, partition_weights, included, &
798 0 : dweights_datom, dweights_dstrain)
799 0 : CPASSERT(feature_end - feature_begin + 1 == COUNT(included))
800 0 : feature_pos = feature_begin
801 0 : DO iatom = 1, natom
802 0 : IF (.NOT. included(iatom)) CYCLE
803 0 : row = features%local_feature_rows(feature_pos)
804 : local_derivative = local_derivative + &
805 0 : partition_weights(iatom)*grid_weight_grad(row)
806 0 : feature_pos = feature_pos + 1
807 : END DO
808 0 : CPASSERT(feature_pos == feature_end + 1)
809 : END IF
810 0 : weight_deriv_r%array(i, j, k) = local_derivative
811 : END DO
812 : END DO
813 : END DO
814 0 : CPASSERT(local_row == features%nflat_local)
815 :
816 0 : IF (ALLOCATED(atom_coords_pbc)) THEN
817 0 : DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, &
818 0 : partition_weights)
819 : END IF
820 0 : CALL torch_tensor_release(grid_weight_grad_t)
821 0 : CALL torch_tensor_release(exc_tensor)
822 0 : CALL skala_gpw_feature_release(features)
823 0 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
824 0 : CALL torch_use_cuda(.TRUE.)
825 :
826 0 : END SUBROUTINE skala_gpw_weight_derivative
827 :
828 : ! **************************************************************************************************
829 : !> \brief Evaluate SKALA on a GAPW one-center atomic grid.
830 : !> \param xc_section ...
831 : !> \param grid_atom ...
832 : !> \param group ...
833 : !> \param atom_coord ...
834 : !> \param rho ...
835 : !> \param drho ...
836 : !> \param tau ...
837 : !> \param weights ...
838 : !> \param lsd ...
839 : !> \param nspins ...
840 : !> \param na ...
841 : !> \param nr ...
842 : !> \param exc ...
843 : !> \param vxc ...
844 : !> \param vxg ...
845 : !> \param vtau ...
846 : !> \param energy_only ...
847 : !> \param atom_force ...
848 : !> \param atom_virial ...
849 : ! **************************************************************************************************
850 36 : SUBROUTINE skala_gapw_atom_vxc_of_r(xc_section, grid_atom, group, atom_coord, &
851 36 : rho, drho, tau, weights, lsd, nspins, na, nr, &
852 : exc, vxc, vxg, vtau, energy_only, atom_force, atom_virial)
853 : TYPE(section_vals_type), POINTER :: xc_section
854 : TYPE(grid_atom_type), POINTER :: grid_atom
855 :
856 : CLASS(mp_comm_type), INTENT(IN) :: group
857 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: atom_coord
858 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: rho, tau, vxc, vtau
859 : REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER :: drho, vxg
860 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: weights
861 : LOGICAL, INTENT(IN) :: lsd
862 : INTEGER, INTENT(IN) :: nspins, na, nr
863 : REAL(KIND=dp), INTENT(OUT) :: exc
864 : LOGICAL, INTENT(IN), OPTIONAL :: energy_only
865 : REAL(KIND=dp), DIMENSION(3), INTENT(OUT), &
866 : OPTIONAL :: atom_force
867 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), &
868 : OPTIONAL :: atom_virial
869 :
870 : CHARACTER(len=default_path_length) :: model_path
871 : INTEGER :: ia, idir, ir, native_grid_cuda_device, &
872 : jdir, nflat, row, selected_cuda_device
873 36 : INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:) :: atomic_grid_sizes
874 36 : INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:, :) :: atomic_grid_size_bound_shape
875 : LOGICAL :: need_coord_grad, my_energy_only, native_grid_use_cuda
876 : REAL(KIND=dp) :: tmp
877 36 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: atomic_grid_weights, grid_weights
878 36 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: coarse_0_atomic_coords, density, &
879 36 : grid_coords, kin
880 36 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: grad
881 36 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: atom_coord_grad, density_grad, &
882 36 : grid_coord_grad, kin_grad
883 36 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: grad_grad
884 : TYPE(section_vals_type), POINTER :: gauxc_section
885 : TYPE(torch_dict_type) :: inputs
886 : TYPE(torch_tensor_type) :: atomic_grid_size_bound_shape_t, &
887 : atomic_grid_sizes_t, &
888 : atomic_grid_weights_t, &
889 : atom_coord_grad_t, &
890 : coarse_0_atomic_coords_t, density_t, &
891 : density_grad_t, exc_tensor, grad_t, &
892 : grad_grad_t, grid_coord_grad_t, &
893 : grid_coords_t, grid_weights_t, kin_t, &
894 : kin_grad_t
895 :
896 0 : CPASSERT(ASSOCIATED(xc_section))
897 36 : CPASSERT(ASSOCIATED(grid_atom))
898 36 : CPASSERT(ASSOCIATED(rho))
899 36 : CPASSERT(ASSOCIATED(drho))
900 36 : CPASSERT(ASSOCIATED(tau))
901 :
902 36 : my_energy_only = .FALSE.
903 36 : IF (PRESENT(energy_only)) my_energy_only = energy_only
904 36 : need_coord_grad = PRESENT(atom_force) .OR. PRESENT(atom_virial)
905 36 : exc = 0.0_dp
906 36 : IF (PRESENT(atom_force)) atom_force = 0.0_dp
907 36 : IF (PRESENT(atom_virial)) atom_virial = 0.0_dp
908 36 : IF (.NOT. my_energy_only) THEN
909 91872 : vxc = 0.0_dp
910 361872 : vxg = 0.0_dp
911 91872 : vtau = 0.0_dp
912 : END IF
913 :
914 36 : CALL get_skala_model_path(xc_section, model_path)
915 36 : gauxc_section => get_gauxc_section(xc_section)
916 36 : CPASSERT(ASSOCIATED(gauxc_section))
917 36 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_USE_CUDA", l_val=native_grid_use_cuda)
918 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_CUDA_DEVICE", &
919 36 : i_val=native_grid_cuda_device)
920 36 : CALL torch_use_cuda(native_grid_use_cuda)
921 : selected_cuda_device = configure_native_grid_cuda( &
922 36 : native_grid_use_cuda, native_grid_cuda_device, group)
923 36 : CALL ensure_model_loaded(model_path, selected_cuda_device)
924 :
925 36 : nflat = na*nr
926 : ALLOCATE (density(nflat, 2), grad(nflat, 3, 2), kin(nflat, 2), &
927 : grid_coords(3, nflat), grid_weights(nflat), &
928 : atomic_grid_weights(nflat), atomic_grid_sizes(1), &
929 468 : coarse_0_atomic_coords(3, 1), atomic_grid_size_bound_shape(0, nflat))
930 36 : density = 0.0_dp
931 36 : grad = 0.0_dp
932 36 : kin = 0.0_dp
933 36 : grid_coords = 0.0_dp
934 36 : grid_weights = 0.0_dp
935 36 : atomic_grid_weights = 0.0_dp
936 36 : atomic_grid_sizes(1) = INT(nflat, KIND=int_8)
937 : atomic_grid_size_bound_shape = 0_int_8
938 144 : coarse_0_atomic_coords(:, 1) = atom_coord
939 :
940 : row = 0
941 1836 : DO ir = 1, nr
942 91836 : DO ia = 1, na
943 90000 : row = row + 1
944 : grid_coords(1, row) = atom_coord(1) + grid_atom%rad(ir)* &
945 90000 : grid_atom%sin_pol(ia)*grid_atom%cos_azi(ia)
946 : grid_coords(2, row) = atom_coord(2) + grid_atom%rad(ir)* &
947 90000 : grid_atom%sin_pol(ia)*grid_atom%sin_azi(ia)
948 90000 : grid_coords(3, row) = atom_coord(3) + grid_atom%rad(ir)*grid_atom%cos_pol(ia)
949 90000 : grid_weights(row) = weights(ia, ir)
950 90000 : atomic_grid_weights(row) = weights(ia, ir)
951 91800 : IF (nspins == 1) THEN
952 270000 : density(row, :) = 0.5_dp*rho(ia, ir, 1)
953 360000 : DO idir = 1, 3
954 900000 : grad(row, idir, :) = 0.5_dp*drho(idir, ia, ir, 1)
955 : END DO
956 270000 : kin(row, :) = 0.5_dp*tau(ia, ir, 1)
957 : ELSE
958 0 : density(row, :) = rho(ia, ir, 1:2)
959 0 : DO idir = 1, 3
960 0 : grad(row, idir, :) = drho(idir, ia, ir, 1:2)
961 : END DO
962 0 : kin(row, :) = tau(ia, ir, 1:2)
963 : END IF
964 : END DO
965 : END DO
966 :
967 36 : CALL torch_tensor_from_array(grid_coords_t, grid_coords)
968 36 : CALL torch_tensor_to_device_leaf(grid_coords_t, need_coord_grad)
969 36 : CALL torch_tensor_from_array(grid_weights_t, grid_weights)
970 36 : CALL torch_tensor_to_device_leaf(grid_weights_t, .FALSE.)
971 36 : CALL torch_tensor_from_array(atomic_grid_weights_t, atomic_grid_weights)
972 36 : CALL torch_tensor_to_device_leaf(atomic_grid_weights_t, .FALSE.)
973 36 : CALL torch_tensor_from_array(atomic_grid_sizes_t, atomic_grid_sizes)
974 36 : CALL torch_tensor_to_device_leaf(atomic_grid_sizes_t, .FALSE.)
975 : CALL torch_tensor_from_array(atomic_grid_size_bound_shape_t, &
976 36 : atomic_grid_size_bound_shape)
977 36 : CALL torch_tensor_to_device_leaf(atomic_grid_size_bound_shape_t, .FALSE.)
978 36 : CALL torch_tensor_from_array(coarse_0_atomic_coords_t, coarse_0_atomic_coords)
979 36 : CALL torch_tensor_to_device_leaf(coarse_0_atomic_coords_t, need_coord_grad)
980 36 : CALL torch_tensor_from_array(density_t, density)
981 36 : CALL torch_tensor_to_device_leaf(density_t,.NOT. my_energy_only)
982 36 : CALL torch_tensor_from_array(grad_t, grad)
983 36 : CALL torch_tensor_to_device_leaf(grad_t,.NOT. my_energy_only)
984 36 : CALL torch_tensor_from_array(kin_t, kin)
985 36 : CALL torch_tensor_to_device_leaf(kin_t,.NOT. my_energy_only)
986 :
987 36 : CALL torch_dict_create(inputs)
988 36 : CALL torch_dict_insert(inputs, "grid_coords", grid_coords_t)
989 36 : CALL torch_dict_insert(inputs, "grid_weights", grid_weights_t)
990 36 : CALL torch_dict_insert(inputs, "atomic_grid_weights", atomic_grid_weights_t)
991 36 : CALL torch_dict_insert(inputs, "atomic_grid_sizes", atomic_grid_sizes_t)
992 : CALL torch_dict_insert(inputs, "atomic_grid_size_bound_shape", &
993 36 : atomic_grid_size_bound_shape_t)
994 36 : CALL torch_dict_insert(inputs, "density", density_t)
995 36 : CALL torch_dict_insert(inputs, "grad", grad_t)
996 36 : CALL torch_dict_insert(inputs, "kin", kin_t)
997 36 : CALL torch_dict_insert(inputs, "coarse_0_atomic_coords", coarse_0_atomic_coords_t)
998 :
999 36 : CALL skala_torch_model_get_exc(cached_model, inputs, grid_weights_t, exc_tensor, exc)
1000 :
1001 36 : IF (.NOT. my_energy_only) THEN
1002 36 : NULLIFY (atom_coord_grad, density_grad, grad_grad, grid_coord_grad, kin_grad)
1003 36 : CALL torch_tensor_backward_scalar(exc_tensor)
1004 36 : IF (need_coord_grad) THEN
1005 36 : CALL torch_tensor_grad(grid_coords_t, grid_coord_grad_t)
1006 36 : CALL torch_tensor_grad(coarse_0_atomic_coords_t, atom_coord_grad_t)
1007 36 : CALL torch_tensor_data_ptr(grid_coord_grad_t, grid_coord_grad)
1008 36 : CALL torch_tensor_data_ptr(atom_coord_grad_t, atom_coord_grad)
1009 36 : IF (PRESENT(atom_force)) THEN
1010 144 : atom_force(:) = atom_coord_grad(:, 1)
1011 90036 : DO row = 1, nflat
1012 360036 : atom_force(:) = atom_force(:) + grid_coord_grad(:, row)
1013 : END DO
1014 : END IF
1015 36 : IF (PRESENT(atom_virial)) THEN
1016 90036 : DO row = 1, nflat
1017 360036 : DO idir = 1, 3
1018 1170000 : DO jdir = 1, 3
1019 810000 : tmp = grid_coord_grad(idir, row)*coarse_0_atomic_coords(jdir, 1)
1020 1080000 : atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
1021 : END DO
1022 : END DO
1023 : END DO
1024 144 : DO idir = 1, 3
1025 468 : DO jdir = 1, 3
1026 324 : tmp = atom_coord_grad(idir, 1)*coarse_0_atomic_coords(jdir, 1)
1027 432 : atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
1028 : END DO
1029 : END DO
1030 : END IF
1031 : END IF
1032 : CALL torch_tensor_grad_batch3(density_t, grad_t, kin_t, density_grad_t, &
1033 36 : grad_grad_t, kin_grad_t)
1034 36 : CALL torch_tensor_data_ptr(density_grad_t, density_grad)
1035 36 : CALL torch_tensor_data_ptr(grad_grad_t, grad_grad)
1036 36 : CALL torch_tensor_data_ptr(kin_grad_t, kin_grad)
1037 :
1038 36 : row = 0
1039 1836 : DO ir = 1, nr
1040 91836 : DO ia = 1, na
1041 90000 : row = row + 1
1042 91800 : IF (lsd) THEN
1043 0 : vxc(ia, ir, 1:2) = density_grad(row, 1:2)
1044 0 : DO idir = 1, 3
1045 0 : vxg(idir, ia, ir, 1:2) = grad_grad(row, idir, 1:2)
1046 : END DO
1047 0 : vtau(ia, ir, 1:2) = kin_grad(row, 1:2)
1048 : ELSE
1049 90000 : vxc(ia, ir, 1) = 0.5_dp*(density_grad(row, 1) + density_grad(row, 2))
1050 360000 : DO idir = 1, 3
1051 : vxg(idir, ia, ir, 1) = &
1052 360000 : 0.5_dp*(grad_grad(row, idir, 1) + grad_grad(row, idir, 2))
1053 : END DO
1054 90000 : vtau(ia, ir, 1) = 0.5_dp*(kin_grad(row, 1) + kin_grad(row, 2))
1055 : END IF
1056 : END DO
1057 : END DO
1058 :
1059 36 : CALL torch_tensor_release(density_grad_t)
1060 36 : CALL torch_tensor_release(grad_grad_t)
1061 36 : CALL torch_tensor_release(kin_grad_t)
1062 36 : IF (need_coord_grad) THEN
1063 36 : CALL torch_tensor_release(grid_coord_grad_t)
1064 36 : CALL torch_tensor_release(atom_coord_grad_t)
1065 : END IF
1066 : END IF
1067 :
1068 36 : CALL torch_tensor_release(exc_tensor)
1069 36 : CALL torch_tensor_release(density_t)
1070 36 : CALL torch_tensor_release(grad_t)
1071 36 : CALL torch_tensor_release(kin_t)
1072 36 : CALL torch_tensor_release(grid_coords_t)
1073 36 : CALL torch_tensor_release(grid_weights_t)
1074 36 : CALL torch_tensor_release(atomic_grid_weights_t)
1075 36 : CALL torch_tensor_release(atomic_grid_sizes_t)
1076 36 : CALL torch_tensor_release(atomic_grid_size_bound_shape_t)
1077 36 : CALL torch_tensor_release(coarse_0_atomic_coords_t)
1078 36 : CALL torch_dict_release(inputs)
1079 0 : DEALLOCATE (atomic_grid_size_bound_shape, atomic_grid_sizes, atomic_grid_weights, &
1080 36 : coarse_0_atomic_coords, density, grad, grid_coords, grid_weights, kin)
1081 36 : CALL torch_use_cuda(.TRUE.)
1082 :
1083 108 : END SUBROUTINE skala_gapw_atom_vxc_of_r
1084 :
1085 : ! **************************************************************************************************
1086 : !> \brief Evaluate a rank-local set of complete atom blocks and sum their SKALA energies.
1087 : !> \param xc_section ...
1088 : !> \param group ...
1089 : !> \param density ...
1090 : !> \param grad ...
1091 : !> \param kin ...
1092 : !> \param grid_coords ...
1093 : !> \param grid_weights ...
1094 : !> \param atomic_grid_weights ...
1095 : !> \param atomic_grid_sizes ...
1096 : !> \param atomic_coords ...
1097 : !> \param exc ...
1098 : !> \param density_grad_out ...
1099 : !> \param grad_grad_out ...
1100 : !> \param kin_grad_out ...
1101 : !> \param grid_coord_grad_out ...
1102 : !> \param grid_weight_grad_out ...
1103 : !> \param atomic_grid_weight_grad_out ...
1104 : !> \param atom_coord_grad_out ...
1105 : ! **************************************************************************************************
1106 28 : SUBROUTINE skala_gapw_atom_composite_energy(xc_section, group, density, grad, kin, &
1107 : grid_coords, grid_weights, atomic_grid_weights, &
1108 : atomic_grid_sizes, atomic_coords, exc, &
1109 : density_grad_out, grad_grad_out, kin_grad_out, &
1110 : grid_coord_grad_out, grid_weight_grad_out, &
1111 : atomic_grid_weight_grad_out, atom_coord_grad_out)
1112 : TYPE(section_vals_type), POINTER :: xc_section
1113 :
1114 : CLASS(mp_comm_type), INTENT(IN) :: group
1115 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), INTENT(IN) :: density, grid_coords, &
1116 : atomic_coords, kin
1117 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), INTENT(IN) :: grad
1118 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), INTENT(IN) :: grid_weights, atomic_grid_weights
1119 : INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:), INTENT(IN) :: atomic_grid_sizes
1120 : REAL(KIND=dp), INTENT(OUT) :: exc
1121 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), INTENT(OUT), OPTIONAL :: density_grad_out, &
1122 : kin_grad_out, &
1123 : grid_coord_grad_out, &
1124 : atom_coord_grad_out
1125 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), INTENT(OUT), OPTIONAL :: grad_grad_out
1126 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), INTENT(OUT), OPTIONAL :: grid_weight_grad_out, &
1127 : atomic_grid_weight_grad_out
1128 :
1129 : CHARACTER(len=default_path_length) :: model_path
1130 : INTEGER :: local_natom, local_nrow, max_grid_size, &
1131 : native_grid_cuda_device, selected_cuda_device
1132 28 : INTEGER(KIND=int_8), ALLOCATABLE, DIMENSION(:, :) :: atomic_grid_size_bound_shape
1133 : LOGICAL :: active_rank, need_coordinate_derivatives, need_derivatives, native_grid_use_cuda
1134 28 : REAL(KIND=dp), DIMENSION(:), POINTER :: atomic_grid_weight_grad, grid_weight_grad
1135 28 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: atom_coord_grad, density_grad, &
1136 28 : grid_coord_grad, kin_grad
1137 28 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: grad_grad
1138 : TYPE(section_vals_type), POINTER :: gauxc_section
1139 : TYPE(torch_dict_type) :: inputs
1140 : TYPE(torch_tensor_type) :: atomic_grid_size_bound_shape_t, &
1141 : atomic_grid_sizes_t, &
1142 : atomic_grid_weight_grad_t, atom_coord_grad_t, &
1143 : density_grad_t, exc_tensor, grad_grad_t, &
1144 : grid_coord_grad_t, grid_weight_grad_t, &
1145 : kin_grad_t
1146 : TYPE(torch_tensor_type), TARGET :: atomic_coords_local_t, &
1147 : atomic_grid_weights_local_t, &
1148 : density_local_t, grad_local_t, &
1149 : grid_coords_local_t, grid_weights_local_t, &
1150 : kin_local_t
1151 : TYPE(torch_tensor_type), POINTER :: atomic_coords_t, atomic_grid_weights_t, &
1152 : density_t, grad_t, grid_coords_t, &
1153 : grid_weights_t, kin_t
1154 :
1155 0 : CPASSERT(ASSOCIATED(xc_section))
1156 28 : CPASSERT(SIZE(density, 1) == SIZE(grid_weights))
1157 28 : CPASSERT(SIZE(density, 1) == SIZE(atomic_grid_weights))
1158 28 : CPASSERT(SIZE(density, 1) == SIZE(grid_coords, 2))
1159 28 : CPASSERT(SIZE(density, 1) == SIZE(grad, 1))
1160 28 : CPASSERT(SIZE(density, 1) == SIZE(kin, 1))
1161 28 : CPASSERT(SIZE(density, 2) == 2)
1162 28 : CPASSERT(SIZE(grad, 2) == 3)
1163 28 : CPASSERT(SIZE(grad, 3) == 2)
1164 28 : CPASSERT(SIZE(kin, 2) == 2)
1165 28 : CPASSERT(SIZE(atomic_grid_sizes) == SIZE(atomic_coords, 2))
1166 56 : CPASSERT(SUM(atomic_grid_sizes) == INT(SIZE(density, 1), KIND=int_8))
1167 28 : need_derivatives = PRESENT(density_grad_out)
1168 28 : CPASSERT(PRESENT(grad_grad_out) .EQV. need_derivatives)
1169 28 : CPASSERT(PRESENT(kin_grad_out) .EQV. need_derivatives)
1170 28 : need_coordinate_derivatives = PRESENT(grid_coord_grad_out)
1171 28 : CPASSERT(PRESENT(grid_weight_grad_out) .EQV. need_coordinate_derivatives)
1172 28 : CPASSERT(PRESENT(atomic_grid_weight_grad_out) .EQV. need_coordinate_derivatives)
1173 28 : CPASSERT(PRESENT(atom_coord_grad_out) .EQV. need_coordinate_derivatives)
1174 28 : CPASSERT((.NOT. need_coordinate_derivatives) .OR. need_derivatives)
1175 :
1176 28 : local_nrow = SIZE(density, 1)
1177 28 : local_natom = SIZE(atomic_grid_sizes)
1178 28 : active_rank = local_natom > 0
1179 28 : CPASSERT(active_rank .EQV. (local_nrow > 0))
1180 :
1181 28 : CALL get_skala_model_path(xc_section, model_path)
1182 28 : gauxc_section => get_gauxc_section(xc_section)
1183 28 : CPASSERT(ASSOCIATED(gauxc_section))
1184 28 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_USE_CUDA", l_val=native_grid_use_cuda)
1185 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_CUDA_DEVICE", &
1186 28 : i_val=native_grid_cuda_device)
1187 28 : CALL torch_use_cuda(native_grid_use_cuda)
1188 : selected_cuda_device = configure_native_grid_cuda( &
1189 28 : native_grid_use_cuda, native_grid_cuda_device, group)
1190 28 : exc = 0.0_dp
1191 28 : IF (active_rank) THEN
1192 26 : CALL ensure_model_loaded(model_path, selected_cuda_device)
1193 :
1194 54 : max_grid_size = INT(MAXVAL(atomic_grid_sizes))
1195 52 : ALLOCATE (atomic_grid_size_bound_shape(0, max_grid_size))
1196 : atomic_grid_size_bound_shape = 0_int_8
1197 :
1198 26 : IF (native_grid_use_cuda) THEN
1199 0 : grid_coords_t => cached_atom_cuda_tensors%grid_coords_t
1200 0 : grid_weights_t => cached_atom_cuda_tensors%grid_weights_t
1201 0 : atomic_grid_weights_t => cached_atom_cuda_tensors%atomic_grid_weights_t
1202 0 : atomic_coords_t => cached_atom_cuda_tensors%atomic_coords_t
1203 0 : density_t => cached_atom_cuda_tensors%density_t
1204 0 : grad_t => cached_atom_cuda_tensors%grad_t
1205 0 : kin_t => cached_atom_cuda_tensors%kin_t
1206 : CALL torch_tensor_reset_from_array( &
1207 0 : grid_coords_t, grid_coords, need_coordinate_derivatives)
1208 : CALL torch_tensor_reset_from_array( &
1209 0 : grid_weights_t, grid_weights, need_coordinate_derivatives)
1210 : CALL torch_tensor_reset_from_array( &
1211 0 : atomic_grid_weights_t, atomic_grid_weights, need_coordinate_derivatives)
1212 : CALL torch_tensor_reset_from_array( &
1213 0 : atomic_coords_t, atomic_coords, need_coordinate_derivatives)
1214 0 : CALL torch_tensor_reset_from_array(density_t, density, need_derivatives)
1215 0 : CALL torch_tensor_reset_from_array(grad_t, grad, need_derivatives)
1216 0 : CALL torch_tensor_reset_from_array(kin_t, kin, need_derivatives)
1217 : ELSE
1218 26 : grid_coords_t => grid_coords_local_t
1219 26 : grid_weights_t => grid_weights_local_t
1220 26 : atomic_grid_weights_t => atomic_grid_weights_local_t
1221 26 : atomic_coords_t => atomic_coords_local_t
1222 26 : density_t => density_local_t
1223 26 : grad_t => grad_local_t
1224 26 : kin_t => kin_local_t
1225 26 : CALL torch_tensor_from_array(grid_coords_t, grid_coords)
1226 26 : CALL torch_tensor_to_device_leaf(grid_coords_t, need_coordinate_derivatives)
1227 26 : CALL torch_tensor_from_array(grid_weights_t, grid_weights)
1228 26 : CALL torch_tensor_to_device_leaf(grid_weights_t, need_coordinate_derivatives)
1229 26 : CALL torch_tensor_from_array(atomic_grid_weights_t, atomic_grid_weights)
1230 26 : CALL torch_tensor_to_device_leaf(atomic_grid_weights_t, need_coordinate_derivatives)
1231 26 : CALL torch_tensor_from_array(atomic_coords_t, atomic_coords)
1232 26 : CALL torch_tensor_to_device_leaf(atomic_coords_t, need_coordinate_derivatives)
1233 26 : CALL torch_tensor_from_array(density_t, density)
1234 26 : CALL torch_tensor_to_device_leaf(density_t, need_derivatives)
1235 26 : CALL torch_tensor_from_array(grad_t, grad)
1236 26 : CALL torch_tensor_to_device_leaf(grad_t, need_derivatives)
1237 26 : CALL torch_tensor_from_array(kin_t, kin)
1238 26 : CALL torch_tensor_to_device_leaf(kin_t, need_derivatives)
1239 : END IF
1240 26 : CALL torch_tensor_from_array(atomic_grid_sizes_t, atomic_grid_sizes)
1241 26 : CALL torch_tensor_to_device_leaf(atomic_grid_sizes_t, .FALSE.)
1242 : CALL torch_tensor_from_array(atomic_grid_size_bound_shape_t, &
1243 26 : atomic_grid_size_bound_shape)
1244 26 : CALL torch_tensor_to_device_leaf(atomic_grid_size_bound_shape_t, .FALSE.)
1245 :
1246 26 : CALL torch_dict_create(inputs)
1247 26 : CALL torch_dict_insert(inputs, "grid_coords", grid_coords_t)
1248 26 : CALL torch_dict_insert(inputs, "grid_weights", grid_weights_t)
1249 26 : CALL torch_dict_insert(inputs, "atomic_grid_weights", atomic_grid_weights_t)
1250 26 : CALL torch_dict_insert(inputs, "atomic_grid_sizes", atomic_grid_sizes_t)
1251 : CALL torch_dict_insert(inputs, "atomic_grid_size_bound_shape", &
1252 26 : atomic_grid_size_bound_shape_t)
1253 26 : CALL torch_dict_insert(inputs, "density", density_t)
1254 26 : CALL torch_dict_insert(inputs, "grad", grad_t)
1255 26 : CALL torch_dict_insert(inputs, "kin", kin_t)
1256 26 : CALL torch_dict_insert(inputs, "coarse_0_atomic_coords", atomic_coords_t)
1257 :
1258 26 : CALL skala_torch_model_get_exc(cached_model, inputs, grid_weights_t, exc_tensor, exc)
1259 : END IF
1260 28 : CALL group%sum(exc)
1261 :
1262 28 : IF (need_derivatives) THEN
1263 0 : ALLOCATE (density_grad_out(local_nrow, 2), grad_grad_out(local_nrow, 3, 2), &
1264 190 : kin_grad_out(local_nrow, 2))
1265 28 : density_grad_out = 0.0_dp
1266 28 : grad_grad_out = 0.0_dp
1267 28 : kin_grad_out = 0.0_dp
1268 28 : IF (active_rank) THEN
1269 26 : NULLIFY (density_grad, grad_grad, kin_grad)
1270 26 : CALL torch_tensor_backward_scalar(exc_tensor)
1271 : CALL torch_tensor_grad_batch3(density_t, grad_t, kin_t, density_grad_t, &
1272 26 : grad_grad_t, kin_grad_t)
1273 26 : CALL torch_tensor_data_ptr(density_grad_t, density_grad)
1274 26 : CALL torch_tensor_data_ptr(grad_grad_t, grad_grad)
1275 26 : CALL torch_tensor_data_ptr(kin_grad_t, kin_grad)
1276 140078 : density_grad_out(:, :) = density_grad
1277 420234 : grad_grad_out(:, :, :) = grad_grad
1278 140078 : kin_grad_out(:, :) = kin_grad
1279 : END IF
1280 :
1281 28 : IF (need_coordinate_derivatives) THEN
1282 0 : ALLOCATE (grid_coord_grad_out(3, local_nrow), grid_weight_grad_out(local_nrow), &
1283 28 : atomic_grid_weight_grad_out(local_nrow), atom_coord_grad_out(3, local_natom))
1284 4 : grid_coord_grad_out = 0.0_dp
1285 4 : grid_weight_grad_out = 0.0_dp
1286 4 : atomic_grid_weight_grad_out = 0.0_dp
1287 4 : atom_coord_grad_out = 0.0_dp
1288 4 : IF (active_rank) THEN
1289 3 : NULLIFY (atomic_grid_weight_grad, atom_coord_grad, grid_coord_grad, grid_weight_grad)
1290 3 : CALL torch_tensor_grad(grid_coords_t, grid_coord_grad_t)
1291 3 : CALL torch_tensor_grad(grid_weights_t, grid_weight_grad_t)
1292 3 : CALL torch_tensor_grad(atomic_grid_weights_t, atomic_grid_weight_grad_t)
1293 3 : CALL torch_tensor_grad(atomic_coords_t, atom_coord_grad_t)
1294 3 : CALL torch_tensor_data_ptr(grid_coord_grad_t, grid_coord_grad)
1295 3 : CALL torch_tensor_data_ptr(grid_weight_grad_t, grid_weight_grad)
1296 3 : CALL torch_tensor_data_ptr(atomic_grid_weight_grad_t, atomic_grid_weight_grad)
1297 3 : CALL torch_tensor_data_ptr(atom_coord_grad_t, atom_coord_grad)
1298 40003 : grid_coord_grad_out(:, :) = grid_coord_grad
1299 10003 : grid_weight_grad_out(:) = grid_weight_grad
1300 10003 : atomic_grid_weight_grad_out(:) = atomic_grid_weight_grad
1301 19 : atom_coord_grad_out(:, :) = atom_coord_grad
1302 3 : CALL torch_tensor_release(grid_coord_grad_t)
1303 3 : CALL torch_tensor_release(grid_weight_grad_t)
1304 3 : CALL torch_tensor_release(atomic_grid_weight_grad_t)
1305 3 : CALL torch_tensor_release(atom_coord_grad_t)
1306 : END IF
1307 : END IF
1308 27 : IF (active_rank) THEN
1309 26 : CALL torch_tensor_release(density_grad_t)
1310 26 : CALL torch_tensor_release(grad_grad_t)
1311 26 : CALL torch_tensor_release(kin_grad_t)
1312 : END IF
1313 : END IF
1314 :
1315 27 : IF (active_rank) THEN
1316 26 : CALL torch_tensor_release(exc_tensor)
1317 26 : IF (.NOT. native_grid_use_cuda) THEN
1318 26 : CALL torch_tensor_release(density_t)
1319 26 : CALL torch_tensor_release(grad_t)
1320 26 : CALL torch_tensor_release(kin_t)
1321 26 : CALL torch_tensor_release(grid_coords_t)
1322 26 : CALL torch_tensor_release(grid_weights_t)
1323 26 : CALL torch_tensor_release(atomic_grid_weights_t)
1324 26 : CALL torch_tensor_release(atomic_coords_t)
1325 : END IF
1326 26 : CALL torch_tensor_release(atomic_grid_sizes_t)
1327 26 : CALL torch_tensor_release(atomic_grid_size_bound_shape_t)
1328 26 : CALL torch_dict_release(inputs)
1329 26 : DEALLOCATE (atomic_grid_size_bound_shape)
1330 : END IF
1331 28 : CALL torch_use_cuda(.TRUE.)
1332 :
1333 56 : END SUBROUTINE skala_gapw_atom_composite_energy
1334 :
1335 : ! **************************************************************************************************
1336 : !> \brief Add the explicit SKALA derivative with respect to atom-center coordinates.
1337 : !> \param atom_force ...
1338 : !> \param features ...
1339 : !> \param atom_coord_grad_t ...
1340 : !> \param root_rank ...
1341 : ! **************************************************************************************************
1342 64 : SUBROUTINE add_explicit_coordinate_force(atom_force, features, atom_coord_grad_t, root_rank)
1343 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: atom_force
1344 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1345 : TYPE(torch_tensor_type), INTENT(INOUT) :: atom_coord_grad_t
1346 : LOGICAL, INTENT(IN) :: root_rank
1347 :
1348 64 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: atom_coord_grad
1349 :
1350 64 : NULLIFY (atom_coord_grad)
1351 64 : CALL torch_tensor_grad(features%coarse_0_atomic_coords_t, atom_coord_grad_t)
1352 64 : IF (root_rank) THEN
1353 32 : CALL torch_tensor_data_ptr(atom_coord_grad_t, atom_coord_grad)
1354 32 : CPASSERT(SIZE(atom_force, 1) == SIZE(atom_coord_grad, 1))
1355 32 : CPASSERT(SIZE(atom_force, 2) == SIZE(atom_coord_grad, 2))
1356 288 : atom_force(:, :) = atom_force(:, :) + atom_coord_grad(:, :)
1357 : END IF
1358 :
1359 64 : END SUBROUTINE add_explicit_coordinate_force
1360 :
1361 : ! **************************************************************************************************
1362 : !> \brief Add the force from SMOOTH native-grid atom partition weights.
1363 : !> \param atom_force ...
1364 : !> \param features ...
1365 : !> \param particle_set ...
1366 : !> \param cell ...
1367 : !> \param rho_r ...
1368 : !> \param grid_weight_grad_t ...
1369 : !> \param atomic_grid_weight_grad_t ...
1370 : ! **************************************************************************************************
1371 64 : SUBROUTINE add_smooth_partition_force(atom_force, features, particle_set, cell, rho_r, &
1372 : grid_weight_grad_t, atomic_grid_weight_grad_t)
1373 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: atom_force
1374 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1375 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1376 : TYPE(cell_type), POINTER :: cell
1377 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
1378 : TYPE(torch_tensor_type), INTENT(INOUT) :: grid_weight_grad_t, &
1379 : atomic_grid_weight_grad_t
1380 :
1381 : INTEGER :: feature_begin, feature_end, feature_pos, &
1382 : i, iatom, j, jatom, k, local_row, &
1383 : natom, row
1384 : INTEGER, DIMENSION(2, 3) :: bo
1385 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: included
1386 : REAL(KIND=dp) :: grid_base_weight, weight_grad
1387 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: weights
1388 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: atom_coords_pbc
1389 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
1390 : REAL(KIND=dp), DIMENSION(3) :: grid_point
1391 64 : REAL(KIND=dp), DIMENSION(:), POINTER :: atomic_grid_weight_grad, grid_weight_grad
1392 :
1393 64 : NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
1394 64 : CALL torch_tensor_grad(features%grid_weights_t, grid_weight_grad_t)
1395 64 : CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
1396 64 : CALL torch_tensor_data_ptr(grid_weight_grad_t, grid_weight_grad)
1397 64 : CALL torch_tensor_data_ptr(atomic_grid_weight_grad_t, atomic_grid_weight_grad)
1398 :
1399 64 : natom = SIZE(particle_set)
1400 64 : CPASSERT(SIZE(atom_force, 1) == 3)
1401 64 : CPASSERT(SIZE(atom_force, 2) == natom)
1402 : ALLOCATE (atom_coords_pbc(3, natom), included(natom), weights(natom), &
1403 768 : dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
1404 192 : DO iatom = 1, natom
1405 192 : atom_coords_pbc(:, iatom) = pbc(particle_set(iatom)%r, cell, positive_range=.TRUE.)
1406 : END DO
1407 :
1408 640 : bo = rho_r(1)%pw_grid%bounds_local
1409 64 : local_row = 0
1410 1402 : DO k = bo(1, 3), bo(2, 3)
1411 30340 : DO j = bo(1, 2), bo(2, 2)
1412 351975 : DO i = bo(1, 1), bo(2, 1)
1413 321699 : local_row = local_row + 1
1414 1286796 : grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
1415 : CALL skala_gpw_smooth_partition_derivatives(grid_point, atom_coords_pbc, cell, &
1416 : weights, included, dweights_datom, &
1417 321699 : dweights_dstrain)
1418 321699 : feature_begin = features%local_feature_offsets(local_row)
1419 321699 : feature_end = features%local_feature_offsets(local_row + 1) - 1
1420 965097 : CPASSERT(feature_end - feature_begin + 1 == COUNT(included))
1421 321699 : grid_base_weight = 0.0_dp
1422 963465 : DO feature_pos = feature_begin, feature_end
1423 641766 : row = features%local_feature_rows(feature_pos)
1424 963465 : grid_base_weight = grid_base_weight + features%grid_weights(row)
1425 : END DO
1426 : feature_pos = feature_begin
1427 965097 : DO iatom = 1, natom
1428 643398 : IF (.NOT. included(iatom)) CYCLE
1429 641766 : row = features%local_feature_rows(feature_pos)
1430 : weight_grad = grid_base_weight*grid_weight_grad(row) + &
1431 : rho_r(1)%pw_grid%dvol*atomic_grid_weight_grad(row)* &
1432 641766 : smooth_partition_atomic_weight_scale_derivative(weights(iatom))
1433 1925298 : DO jatom = 1, natom
1434 : atom_force(:, jatom) = atom_force(:, jatom) + &
1435 5775894 : weight_grad*dweights_datom(:, jatom, iatom)
1436 : END DO
1437 965097 : feature_pos = feature_pos + 1
1438 : END DO
1439 350637 : CPASSERT(feature_pos == feature_end + 1)
1440 : END DO
1441 : END DO
1442 : END DO
1443 64 : CPASSERT(local_row == features%nflat_local)
1444 :
1445 64 : DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, weights)
1446 64 : CALL torch_tensor_release(grid_weight_grad_t)
1447 64 : CALL torch_tensor_release(atomic_grid_weight_grad_t)
1448 :
1449 64 : END SUBROUTINE add_smooth_partition_force
1450 :
1451 : ! **************************************************************************************************
1452 : !> \brief Add the virial from SMOOTH native-grid atom partition weights.
1453 : !> \param virial_xc ...
1454 : !> \param features ...
1455 : !> \param particle_set ...
1456 : !> \param cell ...
1457 : !> \param rho_r ...
1458 : !> \param grid_weight_grad_t ...
1459 : !> \param atomic_grid_weight_grad_t ...
1460 : ! **************************************************************************************************
1461 54 : SUBROUTINE build_smooth_partition_virial(virial_xc, features, particle_set, cell, rho_r, &
1462 : grid_weight_grad_t, atomic_grid_weight_grad_t)
1463 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
1464 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1465 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1466 : TYPE(cell_type), POINTER :: cell
1467 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
1468 : TYPE(torch_tensor_type), INTENT(INOUT) :: grid_weight_grad_t, &
1469 : atomic_grid_weight_grad_t
1470 :
1471 : INTEGER :: feature_begin, feature_end, feature_pos, &
1472 : i, iatom, idir, j, jdir, k, local_row, &
1473 : natom, row
1474 : INTEGER, DIMENSION(2, 3) :: bo
1475 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: included
1476 : REAL(KIND=dp) :: grid_base_weight, tmp, weight_grad
1477 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: weights
1478 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: atom_coords_pbc
1479 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dweights_datom, dweights_dstrain
1480 : REAL(KIND=dp), DIMENSION(3) :: grid_point
1481 54 : REAL(KIND=dp), DIMENSION(:), POINTER :: atomic_grid_weight_grad, grid_weight_grad
1482 :
1483 54 : NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
1484 54 : CALL torch_tensor_grad(features%grid_weights_t, grid_weight_grad_t)
1485 54 : CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
1486 54 : CALL torch_tensor_data_ptr(grid_weight_grad_t, grid_weight_grad)
1487 54 : CALL torch_tensor_data_ptr(atomic_grid_weight_grad_t, atomic_grid_weight_grad)
1488 :
1489 54 : natom = SIZE(particle_set)
1490 : ALLOCATE (atom_coords_pbc(3, natom), included(natom), weights(natom), &
1491 648 : dweights_datom(3, natom, natom), dweights_dstrain(3, 3, natom))
1492 162 : DO iatom = 1, natom
1493 162 : atom_coords_pbc(:, iatom) = pbc(particle_set(iatom)%r, cell, positive_range=.TRUE.)
1494 : END DO
1495 :
1496 540 : bo = rho_r(1)%pw_grid%bounds_local
1497 54 : local_row = 0
1498 1206 : DO k = bo(1, 3), bo(2, 3)
1499 26490 : DO j = bo(1, 2), bo(2, 2)
1500 310362 : DO i = bo(1, 1), bo(2, 1)
1501 283926 : local_row = local_row + 1
1502 1135704 : grid_point = native_grid_coordinate(rho_r(1)%pw_grid, [i, j, k])
1503 : CALL skala_gpw_smooth_partition_derivatives(grid_point, atom_coords_pbc, cell, &
1504 : weights, included, dweights_datom, &
1505 283926 : dweights_dstrain)
1506 283926 : feature_begin = features%local_feature_offsets(local_row)
1507 283926 : feature_end = features%local_feature_offsets(local_row + 1) - 1
1508 851778 : CPASSERT(feature_end - feature_begin + 1 == COUNT(included))
1509 283926 : grid_base_weight = 0.0_dp
1510 850370 : DO feature_pos = feature_begin, feature_end
1511 566444 : row = features%local_feature_rows(feature_pos)
1512 850370 : grid_base_weight = grid_base_weight + features%grid_weights(row)
1513 : END DO
1514 : feature_pos = feature_begin
1515 851778 : DO iatom = 1, natom
1516 567852 : IF (.NOT. included(iatom)) CYCLE
1517 566444 : row = features%local_feature_rows(feature_pos)
1518 : weight_grad = grid_base_weight*grid_weight_grad(row) + &
1519 : rho_r(1)%pw_grid%dvol*atomic_grid_weight_grad(row)* &
1520 566444 : smooth_partition_atomic_weight_scale_derivative(weights(iatom))
1521 2265776 : DO idir = 1, 3
1522 5664440 : DO jdir = 1, idir
1523 3398664 : tmp = weight_grad*dweights_dstrain(idir, jdir, iatom)
1524 3398664 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
1525 5097996 : IF (idir /= jdir) virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
1526 : END DO
1527 : END DO
1528 851778 : feature_pos = feature_pos + 1
1529 : END DO
1530 309210 : CPASSERT(feature_pos == feature_end + 1)
1531 : END DO
1532 : END DO
1533 : END DO
1534 54 : CPASSERT(local_row == features%nflat_local)
1535 :
1536 54 : DEALLOCATE (atom_coords_pbc, dweights_datom, dweights_dstrain, included, weights)
1537 54 : CALL torch_tensor_release(grid_weight_grad_t)
1538 54 : CALL torch_tensor_release(atomic_grid_weight_grad_t)
1539 :
1540 54 : END SUBROUTINE build_smooth_partition_virial
1541 :
1542 : ! **************************************************************************************************
1543 : !> \brief Return the Cartesian coordinate of a regular GPW grid point.
1544 : !> \param pw_grid ...
1545 : !> \param index ...
1546 : !> \return ...
1547 : ! **************************************************************************************************
1548 605625 : FUNCTION native_grid_coordinate(pw_grid, index) RESULT(coord)
1549 : TYPE(pw_grid_type), POINTER :: pw_grid
1550 : INTEGER, DIMENSION(3), INTENT(IN) :: index
1551 : REAL(KIND=dp), DIMENSION(3) :: coord
1552 :
1553 : INTEGER, DIMENSION(3) :: relative_index
1554 :
1555 2422500 : relative_index = index - pw_grid%bounds(1, :)
1556 : coord = REAL(relative_index(1), KIND=dp)*pw_grid%dh(:, 1) + &
1557 : REAL(relative_index(2), KIND=dp)*pw_grid%dh(:, 2) + &
1558 2422500 : REAL(relative_index(3), KIND=dp)*pw_grid%dh(:, 3)
1559 :
1560 605625 : END FUNCTION native_grid_coordinate
1561 :
1562 : ! **************************************************************************************************
1563 : !> \brief Evaluate a rank-local atom chunk as multiple atom-contiguous Torch subchunks.
1564 : !> \param features ...
1565 : !> \param group ...
1566 : !> \param max_rows ...
1567 : !> \param compute_grads ...
1568 : !> \param exc ...
1569 : !> \param density_grad ...
1570 : !> \param grad_grad ...
1571 : !> \param kin_grad ...
1572 : !> \param collapse_spin_grads ...
1573 : ! **************************************************************************************************
1574 2 : SUBROUTINE evaluate_atom_subchunks(features, group, max_rows, compute_grads, exc, &
1575 : density_grad, grad_grad, kin_grad, collapse_spin_grads)
1576 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1577 :
1578 : CLASS(mp_comm_type), INTENT(IN) :: group
1579 : INTEGER, INTENT(IN) :: max_rows
1580 : LOGICAL, INTENT(IN) :: compute_grads, collapse_spin_grads
1581 : REAL(KIND=dp), INTENT(OUT) :: exc
1582 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
1583 : INTENT(OUT) :: density_grad, kin_grad
1584 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
1585 : INTENT(OUT) :: grad_grad
1586 :
1587 : INTEGER :: isubchunk, nroute_grad_per_point, &
1588 : nroute_recv_points, nroute_send_points, &
1589 : nsubchunks, phase_handle, subphase_handle
1590 2 : INTEGER, ALLOCATABLE, DIMENSION(:) :: route_grad_return_recv_counts, &
1591 2 : route_grad_return_recv_displs, &
1592 2 : route_grad_return_send_counts, &
1593 2 : route_grad_return_send_displs, &
1594 2 : subchunk_atom_begin, &
1595 2 : subchunk_atom_count, &
1596 2 : subchunk_row_begin, &
1597 2 : subchunk_row_count
1598 : REAL(KIND=dp) :: subchunk_exc
1599 2 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: recv_grad_buffer, send_grad_buffer
1600 2 : TYPE(skala_gpw_feature_type) :: subchunk
1601 : TYPE(torch_tensor_type) :: subchunk_exc_tensor
1602 :
1603 0 : CPASSERT(features%uses_atom_chunks)
1604 2 : CPASSERT(max_rows > 0)
1605 : CALL skala_gpw_atom_subchunk_layout(max_rows, subchunk_atom_begin, subchunk_atom_count, &
1606 2 : subchunk_row_begin, subchunk_row_count)
1607 2 : nsubchunks = SIZE(subchunk_atom_begin)
1608 :
1609 2 : exc = 0.0_dp
1610 2 : IF (compute_grads) THEN
1611 2 : CPASSERT(features%uses_atom_chunk_routing)
1612 6 : nroute_recv_points = SUM(features%route_point_recv_counts)
1613 2 : nroute_send_points = SIZE(features%route_send_local_rows)
1614 6 : CPASSERT(SUM(features%route_point_send_counts) == nroute_send_points)
1615 2 : CPASSERT(SIZE(features%route_chunk_offsets) == nroute_recv_points + 1)
1616 2 : nroute_grad_per_point = ngrad_per_point
1617 2 : IF (collapse_spin_grads) nroute_grad_per_point = ncollapsed_grad_per_point
1618 : ALLOCATE (send_grad_buffer(MAX(1, nroute_grad_per_point*nroute_recv_points)), &
1619 : recv_grad_buffer(MAX(1, nroute_grad_per_point*nroute_send_points)), &
1620 : route_grad_return_send_counts(SIZE(features%route_point_recv_counts)), &
1621 : route_grad_return_send_displs(SIZE(features%route_point_recv_displs)), &
1622 : route_grad_return_recv_counts(SIZE(features%route_point_send_counts)), &
1623 26 : route_grad_return_recv_displs(SIZE(features%route_point_send_displs)))
1624 : route_grad_return_send_counts(:) = &
1625 6 : nroute_grad_per_point*features%route_point_recv_counts
1626 : route_grad_return_send_displs(:) = &
1627 6 : nroute_grad_per_point*features%route_point_recv_displs
1628 : route_grad_return_recv_counts(:) = &
1629 6 : nroute_grad_per_point*features%route_point_send_counts
1630 : route_grad_return_recv_displs(:) = &
1631 6 : nroute_grad_per_point*features%route_point_send_displs
1632 : END IF
1633 :
1634 2 : CALL timeset("skala_gpw_atom_subchunks", phase_handle)
1635 6 : DO isubchunk = 1, nsubchunks
1636 4 : CALL timeset("skala_gpw_atom_subchunk_build", subphase_handle)
1637 : CALL skala_gpw_feature_build_atom_subchunk_bounds(features, subchunk, &
1638 : subchunk_atom_begin(isubchunk), &
1639 : subchunk_atom_count(isubchunk), &
1640 : subchunk_row_begin(isubchunk), &
1641 : subchunk_row_count(isubchunk), &
1642 4 : compute_grads)
1643 4 : CALL timestop(subphase_handle)
1644 4 : CALL timeset("skala_gpw_atom_subchunk_forward", subphase_handle)
1645 : CALL skala_torch_model_get_exc(cached_model, subchunk%inputs, &
1646 : subchunk%grid_weights_t, subchunk_exc_tensor, &
1647 4 : subchunk_exc)
1648 4 : CALL timestop(subphase_handle)
1649 4 : exc = exc + subchunk_exc
1650 4 : IF (compute_grads) THEN
1651 4 : CALL timeset("skala_gpw_atom_subchunk_backward", subphase_handle)
1652 4 : CALL torch_tensor_backward_scalar(subchunk_exc_tensor)
1653 4 : CALL timestop(subphase_handle)
1654 : END IF
1655 4 : CALL timeset("skala_gpw_atom_subchunk_release", subphase_handle)
1656 4 : CALL torch_tensor_release(subchunk_exc_tensor)
1657 4 : CALL skala_gpw_feature_release(subchunk)
1658 18 : CALL timestop(subphase_handle)
1659 : END DO
1660 2 : IF (compute_grads .AND. features%chunk_feature_count > 0) THEN
1661 2 : CALL timeset("skala_gpw_atom_subchunk_grad_pack", subphase_handle)
1662 2 : CALL pack_atom_chunk_grads(features, send_grad_buffer, .TRUE., collapse_spin_grads)
1663 2 : CALL timestop(subphase_handle)
1664 : END IF
1665 2 : CALL timestop(phase_handle)
1666 :
1667 2 : IF (compute_grads) THEN
1668 2 : CALL timeset("skala_gpw_grad_route_comm", phase_handle)
1669 : CALL group%alltoall(send_grad_buffer, route_grad_return_send_counts, &
1670 : route_grad_return_send_displs, recv_grad_buffer, &
1671 2 : route_grad_return_recv_counts, route_grad_return_recv_displs)
1672 2 : CALL timestop(phase_handle)
1673 :
1674 2 : CALL timeset("skala_gpw_grad_route_scatter", phase_handle)
1675 : CALL scatter_routed_atom_chunk_grads(features, recv_grad_buffer, collapse_spin_grads, &
1676 2 : density_grad, grad_grad, kin_grad)
1677 2 : CALL timestop(phase_handle)
1678 :
1679 0 : DEALLOCATE (recv_grad_buffer, route_grad_return_recv_counts, &
1680 0 : route_grad_return_recv_displs, route_grad_return_send_counts, &
1681 2 : route_grad_return_send_displs, send_grad_buffer)
1682 : END IF
1683 2 : DEALLOCATE (subchunk_atom_begin, subchunk_atom_count, subchunk_row_begin, subchunk_row_count)
1684 :
1685 4 : END SUBROUTINE evaluate_atom_subchunks
1686 :
1687 : ! **************************************************************************************************
1688 : !> \brief Select an automatic atom-subchunk row cap.
1689 : !> \param features ...
1690 : !> \param group ...
1691 : !> \return ...
1692 : ! **************************************************************************************************
1693 250 : FUNCTION auto_atom_chunk_max_rows(features, group) RESULT(max_rows)
1694 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1695 :
1696 : CLASS(mp_comm_type), INTENT(IN) :: group
1697 : INTEGER :: max_rows
1698 :
1699 : INTEGER :: local_rows_max, target_rows
1700 :
1701 250 : local_rows_max = features%chunk_feature_count
1702 250 : CALL group%max(local_rows_max)
1703 250 : IF (local_rows_max <= 0) THEN
1704 250 : max_rows = 0
1705 : RETURN
1706 : END IF
1707 :
1708 250 : IF (group%num_pe > 1) THEN
1709 250 : target_rows = CEILING(REAL(local_rows_max, KIND=dp)/2.0_dp)
1710 : max_rows = atom_chunk_auto_row_quantum* &
1711 250 : ((target_rows + atom_chunk_auto_row_quantum - 1)/atom_chunk_auto_row_quantum)
1712 : ELSE
1713 0 : target_rows = NINT(REAL(local_rows_max, KIND=dp)/4.0_dp)
1714 : max_rows = atom_chunk_auto_row_quantum* &
1715 : MAX(1, NINT(REAL(target_rows, KIND=dp)/ &
1716 0 : REAL(atom_chunk_auto_row_quantum, KIND=dp)))
1717 : END IF
1718 250 : max_rows = MAX(atom_chunk_auto_min_rows, MIN(atom_chunk_auto_max_rows, max_rows))
1719 :
1720 250 : END FUNCTION auto_atom_chunk_max_rows
1721 :
1722 : ! **************************************************************************************************
1723 : !> \brief Map full Torch feature gradients back to this rank's local grid order.
1724 : !> \param features ...
1725 : !> \param density_grad ...
1726 : !> \param grad_grad ...
1727 : !> \param kin_grad ...
1728 : ! **************************************************************************************************
1729 64 : SUBROUTINE fetch_local_feature_grads(features, density_grad, grad_grad, kin_grad)
1730 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1731 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
1732 : INTENT(OUT) :: density_grad
1733 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
1734 : INTENT(OUT) :: grad_grad
1735 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
1736 : INTENT(OUT) :: kin_grad
1737 :
1738 : INTEGER :: feature_pos, i, j, k, local_row, row
1739 64 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: density_grad_all, kin_grad_all
1740 64 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: grad_grad_all
1741 : TYPE(torch_tensor_type) :: density_grad_t, grad_grad_t, kin_grad_t
1742 :
1743 64 : NULLIFY (density_grad_all, grad_grad_all, kin_grad_all)
1744 : CALL get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
1745 64 : density_grad_all, grad_grad_all, kin_grad_all)
1746 64 : CPASSERT(SIZE(density_grad_all, 1) == features%nflat)
1747 64 : CPASSERT(SIZE(density_grad_all, 2) == 2)
1748 64 : CPASSERT(SIZE(grad_grad_all, 1) == features%nflat)
1749 64 : CPASSERT(SIZE(grad_grad_all, 2) == 3)
1750 64 : CPASSERT(SIZE(grad_grad_all, 3) == 2)
1751 64 : CPASSERT(SIZE(kin_grad_all, 1) == features%nflat)
1752 64 : CPASSERT(SIZE(kin_grad_all, 2) == 2)
1753 :
1754 0 : ALLOCATE (density_grad(features%nflat_local, 2), &
1755 0 : grad_grad(features%nflat_local, 3, 2), &
1756 448 : kin_grad(features%nflat_local, 2))
1757 64 : density_grad = 0.0_dp
1758 64 : grad_grad = 0.0_dp
1759 64 : kin_grad = 0.0_dp
1760 64 : local_row = 0
1761 1530 : DO k = LBOUND(features%feature_index, 3), UBOUND(features%feature_index, 3)
1762 33016 : DO j = LBOUND(features%feature_index, 2), UBOUND(features%feature_index, 2)
1763 409851 : DO i = LBOUND(features%feature_index, 1), UBOUND(features%feature_index, 1)
1764 321699 : local_row = local_row + 1
1765 963465 : DO feature_pos = features%local_feature_offsets(local_row), &
1766 350637 : features%local_feature_offsets(local_row + 1) - 1
1767 641766 : row = features%local_feature_rows(feature_pos)
1768 641766 : CPASSERT(row >= 1 .AND. row <= features%nflat)
1769 : density_grad(local_row, :) = density_grad(local_row, :) + &
1770 1925298 : density_grad_all(row, :)
1771 : grad_grad(local_row, :, :) = grad_grad(local_row, :, :) + &
1772 5775894 : grad_grad_all(row, :, :)
1773 2246997 : kin_grad(local_row, :) = kin_grad(local_row, :) + kin_grad_all(row, :)
1774 : END DO
1775 : END DO
1776 : END DO
1777 : END DO
1778 64 : CPASSERT(local_row == features%nflat_local)
1779 :
1780 64 : CALL torch_tensor_release(density_grad_t)
1781 64 : CALL torch_tensor_release(grad_grad_t)
1782 64 : CALL torch_tensor_release(kin_grad_t)
1783 :
1784 64 : END SUBROUTINE fetch_local_feature_grads
1785 :
1786 : ! **************************************************************************************************
1787 : !> \brief Pack atom-chunk Torch gradients into CP2K communication buffers.
1788 : !> \param features ...
1789 : !> \param TARGET ...
1790 : !> \param route_to_return_positions ...
1791 : !> \param collapse_spin_grads ...
1792 : ! **************************************************************************************************
1793 234 : SUBROUTINE pack_atom_chunk_grads(features, TARGET, route_to_return_positions, &
1794 : collapse_spin_grads)
1795 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1796 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
1797 : INTENT(INOUT) :: target
1798 : LOGICAL, INTENT(IN) :: route_to_return_positions
1799 : LOGICAL, INTENT(IN), OPTIONAL :: collapse_spin_grads
1800 :
1801 : INTEGER :: base, feature_pos, irow, &
1802 : ngrad_buffer_per_point, point_pos, &
1803 : target_points
1804 : LOGICAL :: my_collapse_spin_grads
1805 234 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: chunk_density_grad, chunk_kin_grad
1806 234 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: chunk_grad_grad
1807 : TYPE(torch_tensor_type) :: density_grad_t, grad_grad_t, kin_grad_t
1808 :
1809 234 : my_collapse_spin_grads = .FALSE.
1810 468 : IF (PRESENT(collapse_spin_grads)) my_collapse_spin_grads = collapse_spin_grads
1811 234 : ngrad_buffer_per_point = ngrad_per_point
1812 234 : IF (my_collapse_spin_grads) ngrad_buffer_per_point = ncollapsed_grad_per_point
1813 :
1814 234 : NULLIFY (chunk_density_grad, chunk_grad_grad, chunk_kin_grad)
1815 : CALL get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
1816 234 : chunk_density_grad, chunk_grad_grad, chunk_kin_grad)
1817 234 : CPASSERT(MOD(SIZE(TARGET), ngrad_buffer_per_point) == 0)
1818 234 : target_points = SIZE(TARGET)/ngrad_buffer_per_point
1819 234 : CPASSERT(SIZE(chunk_density_grad, 1) == features%chunk_feature_count)
1820 234 : CPASSERT(SIZE(chunk_grad_grad, 1) == features%chunk_feature_count)
1821 234 : CPASSERT(SIZE(chunk_grad_grad, 2) == 3)
1822 234 : CPASSERT(SIZE(chunk_kin_grad, 1) == features%chunk_feature_count)
1823 234 : IF (features%uses_collapsed_rks_dynamic) THEN
1824 188 : CPASSERT(my_collapse_spin_grads)
1825 188 : CPASSERT(SIZE(chunk_density_grad, 2) == 1)
1826 188 : CPASSERT(SIZE(chunk_grad_grad, 3) == 1)
1827 188 : CPASSERT(SIZE(chunk_kin_grad, 2) == 1)
1828 : ELSE
1829 46 : CPASSERT(SIZE(chunk_density_grad, 2) == 2)
1830 46 : CPASSERT(SIZE(chunk_grad_grad, 3) == 2)
1831 46 : CPASSERT(SIZE(chunk_kin_grad, 2) == 2)
1832 : END IF
1833 :
1834 234 : IF (route_to_return_positions) THEN
1835 234 : CPASSERT(target_points == SIZE(features%route_chunk_offsets) - 1)
1836 : !$OMP PARALLEL DO DEFAULT(NONE) &
1837 : !$OMP SHARED(chunk_density_grad, chunk_grad_grad, chunk_kin_grad, features, &
1838 : !$OMP my_collapse_spin_grads, ngrad_buffer_per_point, TARGET, target_points) &
1839 234 : !$OMP PRIVATE(base, feature_pos, irow, point_pos)
1840 : DO point_pos = 1, target_points
1841 : base = ngrad_buffer_per_point*(point_pos - 1)
1842 : TARGET(base + 1:base + ngrad_buffer_per_point) = 0.0_dp
1843 : DO feature_pos = features%route_chunk_offsets(point_pos), &
1844 : features%route_chunk_offsets(point_pos + 1) - 1
1845 : irow = features%route_chunk_rows(feature_pos)
1846 : CPASSERT(irow >= 1 .AND. irow <= features%chunk_feature_count)
1847 : IF (my_collapse_spin_grads) THEN
1848 : IF (features%uses_collapsed_rks_dynamic) THEN
1849 : TARGET(base + 1) = TARGET(base + 1) + &
1850 : 0.5_dp*chunk_density_grad(irow, 1)
1851 : TARGET(base + 2) = TARGET(base + 2) + &
1852 : 0.5_dp*chunk_grad_grad(irow, 1, 1)
1853 : TARGET(base + 3) = TARGET(base + 3) + &
1854 : 0.5_dp*chunk_grad_grad(irow, 2, 1)
1855 : TARGET(base + 4) = TARGET(base + 4) + &
1856 : 0.5_dp*chunk_grad_grad(irow, 3, 1)
1857 : TARGET(base + 5) = TARGET(base + 5) + &
1858 : 0.5_dp*chunk_kin_grad(irow, 1)
1859 : ELSE
1860 : TARGET(base + 1) = TARGET(base + 1) + &
1861 : 0.5_dp*(chunk_density_grad(irow, 1) + &
1862 : chunk_density_grad(irow, 2))
1863 : TARGET(base + 2) = TARGET(base + 2) + &
1864 : 0.5_dp*(chunk_grad_grad(irow, 1, 1) + &
1865 : chunk_grad_grad(irow, 1, 2))
1866 : TARGET(base + 3) = TARGET(base + 3) + &
1867 : 0.5_dp*(chunk_grad_grad(irow, 2, 1) + &
1868 : chunk_grad_grad(irow, 2, 2))
1869 : TARGET(base + 4) = TARGET(base + 4) + &
1870 : 0.5_dp*(chunk_grad_grad(irow, 3, 1) + &
1871 : chunk_grad_grad(irow, 3, 2))
1872 : TARGET(base + 5) = TARGET(base + 5) + &
1873 : 0.5_dp*(chunk_kin_grad(irow, 1) + &
1874 : chunk_kin_grad(irow, 2))
1875 : END IF
1876 : ELSE
1877 : TARGET(base + 1:base + 2) = TARGET(base + 1:base + 2) + &
1878 : chunk_density_grad(irow, :)
1879 : TARGET(base + 3) = TARGET(base + 3) + chunk_grad_grad(irow, 1, 1)
1880 : TARGET(base + 4) = TARGET(base + 4) + chunk_grad_grad(irow, 2, 1)
1881 : TARGET(base + 5) = TARGET(base + 5) + chunk_grad_grad(irow, 3, 1)
1882 : TARGET(base + 6) = TARGET(base + 6) + chunk_grad_grad(irow, 1, 2)
1883 : TARGET(base + 7) = TARGET(base + 7) + chunk_grad_grad(irow, 2, 2)
1884 : TARGET(base + 8) = TARGET(base + 8) + chunk_grad_grad(irow, 3, 2)
1885 : TARGET(base + 9:base + 10) = TARGET(base + 9:base + 10) + &
1886 : chunk_kin_grad(irow, :)
1887 : END IF
1888 : END DO
1889 : END DO
1890 : !$OMP END PARALLEL DO
1891 : ELSE
1892 0 : CPASSERT(target_points >= features%chunk_feature_count)
1893 : !$OMP PARALLEL DO DEFAULT(NONE) &
1894 : !$OMP SHARED(chunk_density_grad, chunk_grad_grad, chunk_kin_grad, features, &
1895 : !$OMP my_collapse_spin_grads, ngrad_buffer_per_point, TARGET) &
1896 0 : !$OMP PRIVATE(base, irow)
1897 : DO irow = 1, features%chunk_feature_count
1898 : base = ngrad_buffer_per_point*(irow - 1)
1899 : IF (my_collapse_spin_grads) THEN
1900 : IF (features%uses_collapsed_rks_dynamic) THEN
1901 : TARGET(base + 1) = 0.5_dp*chunk_density_grad(irow, 1)
1902 : TARGET(base + 2) = 0.5_dp*chunk_grad_grad(irow, 1, 1)
1903 : TARGET(base + 3) = 0.5_dp*chunk_grad_grad(irow, 2, 1)
1904 : TARGET(base + 4) = 0.5_dp*chunk_grad_grad(irow, 3, 1)
1905 : TARGET(base + 5) = 0.5_dp*chunk_kin_grad(irow, 1)
1906 : ELSE
1907 : TARGET(base + 1) = 0.5_dp*(chunk_density_grad(irow, 1) + &
1908 : chunk_density_grad(irow, 2))
1909 : TARGET(base + 2) = 0.5_dp*(chunk_grad_grad(irow, 1, 1) + &
1910 : chunk_grad_grad(irow, 1, 2))
1911 : TARGET(base + 3) = 0.5_dp*(chunk_grad_grad(irow, 2, 1) + &
1912 : chunk_grad_grad(irow, 2, 2))
1913 : TARGET(base + 4) = 0.5_dp*(chunk_grad_grad(irow, 3, 1) + &
1914 : chunk_grad_grad(irow, 3, 2))
1915 : TARGET(base + 5) = 0.5_dp*(chunk_kin_grad(irow, 1) + &
1916 : chunk_kin_grad(irow, 2))
1917 : END IF
1918 : ELSE
1919 : TARGET(base + 1:base + 2) = chunk_density_grad(irow, :)
1920 : TARGET(base + 3) = chunk_grad_grad(irow, 1, 1)
1921 : TARGET(base + 4) = chunk_grad_grad(irow, 2, 1)
1922 : TARGET(base + 5) = chunk_grad_grad(irow, 3, 1)
1923 : TARGET(base + 6) = chunk_grad_grad(irow, 1, 2)
1924 : TARGET(base + 7) = chunk_grad_grad(irow, 2, 2)
1925 : TARGET(base + 8) = chunk_grad_grad(irow, 3, 2)
1926 : TARGET(base + 9:base + 10) = chunk_kin_grad(irow, :)
1927 : END IF
1928 : END DO
1929 : !$OMP END PARALLEL DO
1930 : END IF
1931 :
1932 234 : CALL torch_tensor_release(density_grad_t)
1933 234 : CALL torch_tensor_release(grad_grad_t)
1934 234 : CALL torch_tensor_release(kin_grad_t)
1935 :
1936 234 : END SUBROUTINE pack_atom_chunk_grads
1937 :
1938 : ! **************************************************************************************************
1939 : !> \brief Scatter routed atom-chunk gradients into local grid-row order.
1940 : !> \param features ...
1941 : !> \param recv_grad_buffer ...
1942 : !> \param collapse_spin_grads ...
1943 : !> \param density_grad ...
1944 : !> \param grad_grad ...
1945 : !> \param kin_grad ...
1946 : ! **************************************************************************************************
1947 234 : SUBROUTINE scatter_routed_atom_chunk_grads(features, recv_grad_buffer, collapse_spin_grads, &
1948 : density_grad, grad_grad, kin_grad)
1949 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
1950 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: recv_grad_buffer
1951 : LOGICAL, INTENT(IN) :: collapse_spin_grads
1952 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
1953 : INTENT(OUT) :: density_grad
1954 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
1955 : INTENT(OUT) :: grad_grad
1956 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
1957 : INTENT(OUT) :: kin_grad
1958 :
1959 : INTEGER :: base, local_row, nflat_local, &
1960 : nroute_grad_per_point, nroute_points, &
1961 : point_pos, row_route_pos
1962 :
1963 234 : nflat_local = features%nflat_local
1964 234 : nroute_points = SIZE(features%route_send_local_rows)
1965 234 : nroute_grad_per_point = ngrad_per_point
1966 234 : IF (collapse_spin_grads) nroute_grad_per_point = ncollapsed_grad_per_point
1967 234 : CPASSERT(SIZE(recv_grad_buffer) >= nroute_grad_per_point*nroute_points)
1968 0 : ALLOCATE (density_grad(nflat_local, 2), grad_grad(nflat_local, 3, 2), &
1969 1638 : kin_grad(nflat_local, 2))
1970 :
1971 : !$OMP PARALLEL DO DEFAULT(NONE) &
1972 : !$OMP SHARED(collapse_spin_grads, density_grad, features, grad_grad, kin_grad, nflat_local, &
1973 : !$OMP nroute_grad_per_point, nroute_points, recv_grad_buffer) &
1974 234 : !$OMP PRIVATE(base, local_row, point_pos, row_route_pos)
1975 : DO local_row = 1, nflat_local
1976 : density_grad(local_row, :) = 0.0_dp
1977 : grad_grad(local_row, :, :) = 0.0_dp
1978 : kin_grad(local_row, :) = 0.0_dp
1979 : DO row_route_pos = features%route_row_offsets(local_row), &
1980 : features%route_row_offsets(local_row + 1) - 1
1981 : point_pos = features%route_row_positions(row_route_pos)
1982 : CPASSERT(point_pos >= 1 .AND. point_pos <= nroute_points)
1983 : base = nroute_grad_per_point*(point_pos - 1)
1984 : IF (collapse_spin_grads) THEN
1985 : density_grad(local_row, :) = density_grad(local_row, :) + &
1986 : recv_grad_buffer(base + 1)
1987 : grad_grad(local_row, 1, :) = grad_grad(local_row, 1, :) + &
1988 : recv_grad_buffer(base + 2)
1989 : grad_grad(local_row, 2, :) = grad_grad(local_row, 2, :) + &
1990 : recv_grad_buffer(base + 3)
1991 : grad_grad(local_row, 3, :) = grad_grad(local_row, 3, :) + &
1992 : recv_grad_buffer(base + 4)
1993 : kin_grad(local_row, :) = kin_grad(local_row, :) + recv_grad_buffer(base + 5)
1994 : ELSE
1995 : density_grad(local_row, :) = density_grad(local_row, :) + &
1996 : recv_grad_buffer(base + 1:base + 2)
1997 : grad_grad(local_row, 1, 1) = grad_grad(local_row, 1, 1) + &
1998 : recv_grad_buffer(base + 3)
1999 : grad_grad(local_row, 2, 1) = grad_grad(local_row, 2, 1) + &
2000 : recv_grad_buffer(base + 4)
2001 : grad_grad(local_row, 3, 1) = grad_grad(local_row, 3, 1) + &
2002 : recv_grad_buffer(base + 5)
2003 : grad_grad(local_row, 1, 2) = grad_grad(local_row, 1, 2) + &
2004 : recv_grad_buffer(base + 6)
2005 : grad_grad(local_row, 2, 2) = grad_grad(local_row, 2, 2) + &
2006 : recv_grad_buffer(base + 7)
2007 : grad_grad(local_row, 3, 2) = grad_grad(local_row, 3, 2) + &
2008 : recv_grad_buffer(base + 8)
2009 : kin_grad(local_row, :) = kin_grad(local_row, :) + &
2010 : recv_grad_buffer(base + 9:base + 10)
2011 : END IF
2012 : END DO
2013 : END DO
2014 : !$OMP END PARALLEL DO
2015 :
2016 234 : END SUBROUTINE scatter_routed_atom_chunk_grads
2017 :
2018 : ! **************************************************************************************************
2019 : !> \brief Return CPU views of autograd outputs for the SKALA dynamic feature tensors.
2020 : !> \param features ...
2021 : !> \param density_grad_t ...
2022 : !> \param grad_grad_t ...
2023 : !> \param kin_grad_t ...
2024 : !> \param density_grad ...
2025 : !> \param grad_grad ...
2026 : !> \param kin_grad ...
2027 : ! **************************************************************************************************
2028 298 : SUBROUTINE get_feature_grad_views(features, density_grad_t, grad_grad_t, kin_grad_t, &
2029 : density_grad, grad_grad, kin_grad)
2030 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
2031 : TYPE(torch_tensor_type), INTENT(INOUT) :: density_grad_t, grad_grad_t, kin_grad_t
2032 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: density_grad
2033 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: grad_grad
2034 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: kin_grad
2035 :
2036 298 : NULLIFY (density_grad, grad_grad, kin_grad)
2037 : CALL torch_tensor_grad_batch3(features%density_t, features%grad_t, features%kin_t, &
2038 298 : density_grad_t, grad_grad_t, kin_grad_t)
2039 298 : CALL torch_tensor_data_ptr(density_grad_t, density_grad)
2040 298 : CALL torch_tensor_data_ptr(grad_grad_t, grad_grad)
2041 298 : CALL torch_tensor_data_ptr(kin_grad_t, kin_grad)
2042 :
2043 298 : END SUBROUTINE get_feature_grad_views
2044 :
2045 : ! **************************************************************************************************
2046 : !> \brief Fetch atom-chunk gradients and route them back to their local grid owners.
2047 : !> \param features ...
2048 : !> \param group ...
2049 : !> \param density_grad ...
2050 : !> \param grad_grad ...
2051 : !> \param kin_grad ...
2052 : ! **************************************************************************************************
2053 232 : SUBROUTINE fetch_and_gather_atom_chunk_grads(features, group, density_grad, grad_grad, &
2054 : kin_grad)
2055 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
2056 :
2057 : CLASS(mp_comm_type), INTENT(IN) :: group
2058 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
2059 : INTENT(OUT) :: density_grad, kin_grad
2060 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
2061 : INTENT(OUT) :: grad_grad
2062 :
2063 : INTEGER :: base, feature_pos, i, j, k, local_row, &
2064 : nflat_local, nroute_grad_per_point, &
2065 : nroute_recv_points, nroute_send_points, &
2066 : phase_handle, row
2067 232 : INTEGER, ALLOCATABLE, DIMENSION(:) :: route_grad_return_recv_counts, &
2068 232 : route_grad_return_recv_displs, &
2069 232 : route_grad_return_send_counts, &
2070 232 : route_grad_return_send_displs
2071 232 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: chunk_grad_buffer, global_grad_buffer, &
2072 232 : recv_grad_buffer, send_grad_buffer
2073 :
2074 232 : CPASSERT(features%uses_atom_chunks)
2075 :
2076 232 : nflat_local = features%nflat_local
2077 232 : IF (features%uses_atom_chunk_routing) THEN
2078 696 : nroute_recv_points = SUM(features%route_point_recv_counts)
2079 232 : nroute_send_points = SIZE(features%route_send_local_rows)
2080 696 : CPASSERT(SUM(features%route_point_send_counts) == nroute_send_points)
2081 232 : CPASSERT(SIZE(features%route_chunk_offsets) == nroute_recv_points + 1)
2082 :
2083 232 : nroute_grad_per_point = ngrad_per_point
2084 232 : IF (features%uses_collapsed_rks_dynamic) THEN
2085 186 : nroute_grad_per_point = ncollapsed_grad_per_point
2086 : END IF
2087 : ALLOCATE (send_grad_buffer(MAX(1, nroute_grad_per_point*nroute_recv_points)), &
2088 : recv_grad_buffer(MAX(1, nroute_grad_per_point*nroute_send_points)), &
2089 : route_grad_return_send_counts(SIZE(features%route_point_recv_counts)), &
2090 : route_grad_return_send_displs(SIZE(features%route_point_recv_displs)), &
2091 : route_grad_return_recv_counts(SIZE(features%route_point_send_counts)), &
2092 3016 : route_grad_return_recv_displs(SIZE(features%route_point_send_displs)))
2093 : route_grad_return_send_counts(:) = &
2094 696 : nroute_grad_per_point*features%route_point_recv_counts
2095 : route_grad_return_send_displs(:) = &
2096 696 : nroute_grad_per_point*features%route_point_recv_displs
2097 : route_grad_return_recv_counts(:) = &
2098 696 : nroute_grad_per_point*features%route_point_send_counts
2099 : route_grad_return_recv_displs(:) = &
2100 696 : nroute_grad_per_point*features%route_point_send_displs
2101 :
2102 232 : IF (features%chunk_feature_count > 0) THEN
2103 232 : CALL timeset("skala_gpw_grad_torch_pack", phase_handle)
2104 : CALL pack_atom_chunk_grads(features, send_grad_buffer, .TRUE., &
2105 232 : features%uses_collapsed_rks_dynamic)
2106 232 : CALL timestop(phase_handle)
2107 : END IF
2108 :
2109 232 : CALL timeset("skala_gpw_grad_route_comm", phase_handle)
2110 : CALL group%alltoall(send_grad_buffer, route_grad_return_send_counts, &
2111 : route_grad_return_send_displs, recv_grad_buffer, &
2112 232 : route_grad_return_recv_counts, route_grad_return_recv_displs)
2113 232 : CALL timestop(phase_handle)
2114 :
2115 232 : CALL timeset("skala_gpw_grad_route_scatter", phase_handle)
2116 : CALL scatter_routed_atom_chunk_grads(features, recv_grad_buffer, &
2117 : features%uses_collapsed_rks_dynamic, &
2118 232 : density_grad, grad_grad, kin_grad)
2119 232 : CALL timestop(phase_handle)
2120 :
2121 0 : DEALLOCATE (recv_grad_buffer, route_grad_return_recv_counts, &
2122 0 : route_grad_return_recv_displs, route_grad_return_send_counts, &
2123 696 : route_grad_return_send_displs, send_grad_buffer)
2124 : ELSE
2125 : ALLOCATE (chunk_grad_buffer(MAX(1, ngrad_per_point*features%chunk_feature_count)), &
2126 0 : global_grad_buffer(ngrad_per_point*features%nflat))
2127 0 : IF (features%chunk_feature_count > 0) THEN
2128 0 : CALL timeset("skala_gpw_grad_torch_pack", phase_handle)
2129 0 : CALL pack_atom_chunk_grads(features, chunk_grad_buffer, .FALSE.)
2130 0 : CALL timestop(phase_handle)
2131 : END IF
2132 :
2133 0 : CALL timeset("skala_gpw_grad_allgatherv", phase_handle)
2134 : CALL group%allgatherv(chunk_grad_buffer, global_grad_buffer, &
2135 0 : features%chunk_grad_counts, features%chunk_grad_displs)
2136 0 : CALL timestop(phase_handle)
2137 :
2138 0 : CALL timeset("skala_gpw_grad_scatter", phase_handle)
2139 0 : ALLOCATE (density_grad(nflat_local, 2), grad_grad(nflat_local, 3, 2), &
2140 0 : kin_grad(nflat_local, 2))
2141 0 : density_grad = 0.0_dp
2142 0 : grad_grad = 0.0_dp
2143 0 : kin_grad = 0.0_dp
2144 0 : local_row = 0
2145 0 : DO k = LBOUND(features%feature_index, 3), UBOUND(features%feature_index, 3)
2146 0 : DO j = LBOUND(features%feature_index, 2), UBOUND(features%feature_index, 2)
2147 0 : DO i = LBOUND(features%feature_index, 1), UBOUND(features%feature_index, 1)
2148 0 : local_row = local_row + 1
2149 0 : DO feature_pos = features%local_feature_offsets(local_row), &
2150 0 : features%local_feature_offsets(local_row + 1) - 1
2151 0 : row = features%local_feature_rows(feature_pos)
2152 0 : CPASSERT(row >= 1 .AND. row <= features%nflat)
2153 0 : base = ngrad_per_point*(row - 1)
2154 : density_grad(local_row, :) = density_grad(local_row, :) + &
2155 0 : global_grad_buffer(base + 1:base + 2)
2156 : grad_grad(local_row, 1, 1) = grad_grad(local_row, 1, 1) + &
2157 0 : global_grad_buffer(base + 3)
2158 : grad_grad(local_row, 2, 1) = grad_grad(local_row, 2, 1) + &
2159 0 : global_grad_buffer(base + 4)
2160 : grad_grad(local_row, 3, 1) = grad_grad(local_row, 3, 1) + &
2161 0 : global_grad_buffer(base + 5)
2162 : grad_grad(local_row, 1, 2) = grad_grad(local_row, 1, 2) + &
2163 0 : global_grad_buffer(base + 6)
2164 : grad_grad(local_row, 2, 2) = grad_grad(local_row, 2, 2) + &
2165 0 : global_grad_buffer(base + 7)
2166 : grad_grad(local_row, 3, 2) = grad_grad(local_row, 3, 2) + &
2167 0 : global_grad_buffer(base + 8)
2168 : kin_grad(local_row, :) = kin_grad(local_row, :) + &
2169 0 : global_grad_buffer(base + 9:base + 10)
2170 : END DO
2171 : END DO
2172 : END DO
2173 : END DO
2174 0 : CALL timestop(phase_handle)
2175 0 : DEALLOCATE (chunk_grad_buffer, global_grad_buffer)
2176 :
2177 : END IF
2178 :
2179 232 : END SUBROUTINE fetch_and_gather_atom_chunk_grads
2180 :
2181 : ! **************************************************************************************************
2182 : !> \brief Build the native SKALA XC virial from feature gradients.
2183 : !> \param virial_xc ...
2184 : !> \param rho_set ...
2185 : !> \param rho_r ...
2186 : !> \param grad_grad ...
2187 : ! **************************************************************************************************
2188 54 : SUBROUTINE build_virial_from_feature_grads(virial_xc, rho_set, rho_r, grad_grad)
2189 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
2190 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set
2191 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
2192 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: grad_grad
2193 :
2194 : INTEGER :: i, idir, ipt, ispin, j, jdir, k, nspins
2195 : INTEGER, DIMENSION(2, 3) :: bo
2196 : REAL(KIND=dp) :: grad_i, tmp
2197 648 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drhoa, drhob
2198 :
2199 54 : nspins = SIZE(rho_r)
2200 540 : bo = rho_r(1)%pw_grid%bounds_local
2201 54 : ipt = 0
2202 :
2203 54 : IF (nspins == 1) THEN
2204 54 : CALL xc_rho_set_get(rho_set, drho=drho)
2205 1206 : DO k = bo(1, 3), bo(2, 3)
2206 26490 : DO j = bo(1, 2), bo(2, 2)
2207 310362 : DO i = bo(1, 1), bo(2, 1)
2208 283926 : ipt = ipt + 1
2209 1160988 : DO idir = 1, 3
2210 851778 : grad_i = 0.5_dp*(grad_grad(ipt, idir, 1) + grad_grad(ipt, idir, 2))
2211 3691038 : DO jdir = 1, 3
2212 2555334 : tmp = -grad_i*drho(jdir)%array(i, j, k)
2213 3407112 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2214 : END DO
2215 : END DO
2216 : END DO
2217 : END DO
2218 : END DO
2219 : ELSE
2220 0 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob)
2221 0 : DO k = bo(1, 3), bo(2, 3)
2222 0 : DO j = bo(1, 2), bo(2, 2)
2223 0 : DO i = bo(1, 1), bo(2, 1)
2224 0 : ipt = ipt + 1
2225 0 : DO idir = 1, 3
2226 0 : DO jdir = 1, 3
2227 : tmp = 0.0_dp
2228 0 : DO ispin = 1, 2
2229 0 : IF (ispin == 1) THEN
2230 0 : tmp = tmp - grad_grad(ipt, idir, ispin)*drhoa(jdir)%array(i, j, k)
2231 : ELSE
2232 0 : tmp = tmp - grad_grad(ipt, idir, ispin)*drhob(jdir)%array(i, j, k)
2233 : END IF
2234 : END DO
2235 0 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2236 : END DO
2237 : END DO
2238 : END DO
2239 : END DO
2240 : END DO
2241 : END IF
2242 :
2243 54 : END SUBROUTINE build_virial_from_feature_grads
2244 :
2245 : ! **************************************************************************************************
2246 : !> \brief Print a native SKALA XC virial contribution for diagnostics.
2247 : !> \param label ...
2248 : !> \param delta ...
2249 : !> \param root_rank ...
2250 : ! **************************************************************************************************
2251 20 : SUBROUTINE print_virial_delta(label, delta, root_rank)
2252 : CHARACTER(LEN=*), INTENT(IN) :: label
2253 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: delta
2254 : LOGICAL, INTENT(IN) :: root_rank
2255 :
2256 : INTEGER :: i, iw
2257 :
2258 20 : IF (.NOT. root_rank) RETURN
2259 12 : iw = cp_logger_get_default_io_unit()
2260 12 : IF (iw <= 0) RETURN
2261 12 : WRITE (iw, "(T2,A,1X,A)") "SKALA_GPW| XC virial contribution", TRIM(label)
2262 48 : DO i = 1, 3
2263 48 : WRITE (iw, "(T2,A,1X,3ES20.10)") "SKALA_GPW|", delta(i, 1:3)
2264 : END DO
2265 :
2266 : END SUBROUTINE print_virial_delta
2267 :
2268 : ! **************************************************************************************************
2269 : !> \brief Add explicit SKALA coordinate-feature contributions to the XC virial.
2270 : !> \param virial_xc ...
2271 : !> \param features ...
2272 : !> \param atom_coord_grad_t ...
2273 : !> \param grid_coord_grad_t ...
2274 : !> \param root_rank ...
2275 : !> \param print_components ...
2276 : ! **************************************************************************************************
2277 54 : SUBROUTINE build_static_coordinate_virial(virial_xc, features, atom_coord_grad_t, &
2278 : grid_coord_grad_t, root_rank, print_components)
2279 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
2280 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
2281 : TYPE(torch_tensor_type), INTENT(INOUT) :: atom_coord_grad_t, grid_coord_grad_t
2282 : LOGICAL, INTENT(IN) :: root_rank
2283 : LOGICAL, INTENT(IN), OPTIONAL :: print_components
2284 :
2285 : INTEGER :: feature_pos, i, iatom, idir, iw, j, &
2286 : jdir, k, local_row, row
2287 : LOGICAL :: my_print_components
2288 : REAL(KIND=dp) :: tmp
2289 : REAL(KIND=dp), DIMENSION(3) :: atom_grad_sum, grid_grad_sum
2290 : REAL(KIND=dp), DIMENSION(3, 3) :: atom_virial, grid_virial
2291 54 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: atom_coord_grad, grid_coord_grad
2292 :
2293 54 : my_print_components = .FALSE.
2294 54 : IF (PRESENT(print_components)) my_print_components = print_components
2295 :
2296 54 : NULLIFY (atom_coord_grad, grid_coord_grad)
2297 54 : CALL torch_tensor_grad(features%grid_coords_t, grid_coord_grad_t)
2298 54 : CALL torch_tensor_data_ptr(grid_coord_grad_t, grid_coord_grad)
2299 54 : CALL torch_tensor_data_ptr(atom_coord_grad_t, atom_coord_grad)
2300 :
2301 54 : grid_virial = 0.0_dp
2302 54 : atom_virial = 0.0_dp
2303 54 : grid_grad_sum = 0.0_dp
2304 54 : atom_grad_sum = 0.0_dp
2305 54 : local_row = 0
2306 1314 : DO k = LBOUND(features%feature_index, 3), UBOUND(features%feature_index, 3)
2307 28794 : DO j = LBOUND(features%feature_index, 2), UBOUND(features%feature_index, 2)
2308 360930 : DO i = LBOUND(features%feature_index, 1), UBOUND(features%feature_index, 1)
2309 283926 : local_row = local_row + 1
2310 850370 : DO feature_pos = features%local_feature_offsets(local_row), &
2311 309210 : features%local_feature_offsets(local_row + 1) - 1
2312 566444 : row = features%local_feature_rows(feature_pos)
2313 2265776 : grid_grad_sum(:) = grid_grad_sum(:) + grid_coord_grad(:, row)
2314 2549702 : DO idir = 1, 3
2315 7363772 : DO jdir = 1, 3
2316 5097996 : tmp = grid_coord_grad(idir, row)*features%grid_coords(jdir, row)
2317 5097996 : grid_virial(idir, jdir) = grid_virial(idir, jdir) + tmp
2318 6797328 : virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
2319 : END DO
2320 : END DO
2321 : END DO
2322 : END DO
2323 : END DO
2324 : END DO
2325 54 : CPASSERT(local_row == features%nflat_local)
2326 :
2327 54 : IF (root_rank) THEN
2328 81 : DO iatom = 1, SIZE(features%coarse_0_atomic_coords, 2)
2329 216 : atom_grad_sum(:) = atom_grad_sum(:) + atom_coord_grad(:, iatom)
2330 243 : DO idir = 1, 3
2331 702 : DO jdir = 1, 3
2332 486 : tmp = atom_coord_grad(idir, iatom)*features%coarse_0_atomic_coords(jdir, iatom)
2333 486 : atom_virial(idir, jdir) = atom_virial(idir, jdir) + tmp
2334 648 : virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
2335 : END DO
2336 : END DO
2337 : END DO
2338 : END IF
2339 :
2340 54 : IF (my_print_components .AND. root_rank) THEN
2341 2 : iw = cp_logger_get_default_io_unit()
2342 2 : IF (iw > 0) THEN
2343 2 : CALL print_virial_delta("static-grid", grid_virial, .TRUE.)
2344 2 : CALL print_virial_delta("static-atom", atom_virial, .TRUE.)
2345 2 : WRITE (iw, "(T2,A,1X,3ES20.10)") "SKALA_GPW| XC coordinate gradient grid sum", &
2346 4 : grid_grad_sum
2347 2 : WRITE (iw, "(T2,A,1X,3ES20.10)") "SKALA_GPW| XC coordinate gradient atom sum", &
2348 4 : atom_grad_sum
2349 2 : WRITE (iw, "(T2,A,1X,3ES20.10)") "SKALA_GPW| XC coordinate gradient total sum", &
2350 10 : grid_grad_sum + atom_grad_sum
2351 : END IF
2352 : END IF
2353 :
2354 54 : CALL torch_tensor_release(grid_coord_grad_t)
2355 :
2356 54 : END SUBROUTINE build_static_coordinate_virial
2357 :
2358 : ! **************************************************************************************************
2359 : !> \brief Add residual SKALA weight-feature contributions to the XC virial.
2360 : !> \param virial_xc ...
2361 : !> \param features ...
2362 : !> \param exc ...
2363 : !> \param grid_weight_grad_t ...
2364 : !> \param atomic_grid_weight_grad_t ...
2365 : !> \param root_rank ...
2366 : !> \param print_components ...
2367 : ! **************************************************************************************************
2368 54 : SUBROUTINE build_weight_virial(virial_xc, features, exc, grid_weight_grad_t, &
2369 : atomic_grid_weight_grad_t, root_rank, print_components)
2370 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
2371 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
2372 : REAL(KIND=dp), INTENT(IN) :: exc
2373 : TYPE(torch_tensor_type), INTENT(INOUT) :: grid_weight_grad_t, &
2374 : atomic_grid_weight_grad_t
2375 : LOGICAL, INTENT(IN) :: root_rank
2376 : LOGICAL, INTENT(IN), OPTIONAL :: print_components
2377 :
2378 : INTEGER :: feature_pos, i, idir, iw, j, k, &
2379 : local_row, row
2380 : LOGICAL :: my_print_components
2381 : REAL(KIND=dp) :: atomic_tmp, exc_tmp, grid_tmp, tmp
2382 54 : REAL(KIND=dp), DIMENSION(:), POINTER :: atomic_grid_weight_grad, grid_weight_grad
2383 :
2384 54 : my_print_components = .FALSE.
2385 54 : IF (PRESENT(print_components)) my_print_components = print_components
2386 :
2387 54 : NULLIFY (atomic_grid_weight_grad, grid_weight_grad)
2388 54 : CALL torch_tensor_grad(features%grid_weights_t, grid_weight_grad_t)
2389 54 : CALL torch_tensor_grad(features%atomic_grid_weights_t, atomic_grid_weight_grad_t)
2390 54 : CALL torch_tensor_data_ptr(grid_weight_grad_t, grid_weight_grad)
2391 54 : CALL torch_tensor_data_ptr(atomic_grid_weight_grad_t, atomic_grid_weight_grad)
2392 :
2393 54 : grid_tmp = 0.0_dp
2394 54 : atomic_tmp = 0.0_dp
2395 54 : local_row = 0
2396 1314 : DO k = LBOUND(features%feature_index, 3), UBOUND(features%feature_index, 3)
2397 28794 : DO j = LBOUND(features%feature_index, 2), UBOUND(features%feature_index, 2)
2398 360930 : DO i = LBOUND(features%feature_index, 1), UBOUND(features%feature_index, 1)
2399 283926 : local_row = local_row + 1
2400 850370 : DO feature_pos = features%local_feature_offsets(local_row), &
2401 309210 : features%local_feature_offsets(local_row + 1) - 1
2402 566444 : row = features%local_feature_rows(feature_pos)
2403 566444 : grid_tmp = grid_tmp + grid_weight_grad(row)*features%grid_weights(row)
2404 : atomic_tmp = atomic_tmp + &
2405 850370 : atomic_grid_weight_grad(row)*features%atomic_grid_weights(row)
2406 : END DO
2407 : END DO
2408 : END DO
2409 : END DO
2410 54 : CPASSERT(local_row == features%nflat_local)
2411 54 : exc_tmp = 0.0_dp
2412 54 : IF (root_rank) exc_tmp = -exc
2413 54 : tmp = grid_tmp + atomic_tmp + exc_tmp
2414 :
2415 54 : IF (my_print_components .AND. root_rank) THEN
2416 2 : iw = cp_logger_get_default_io_unit()
2417 2 : IF (iw > 0) THEN
2418 2 : WRITE (iw, "(T2,A,1X,ES20.10)") "SKALA_GPW| XC virial weight grid", grid_tmp
2419 2 : WRITE (iw, "(T2,A,1X,ES20.10)") "SKALA_GPW| XC virial weight atomic", atomic_tmp
2420 2 : WRITE (iw, "(T2,A,1X,ES20.10)") "SKALA_GPW| XC virial weight final", exc_tmp
2421 2 : WRITE (iw, "(T2,A,1X,ES20.10)") "SKALA_GPW| XC virial weight residual", tmp
2422 : END IF
2423 : END IF
2424 :
2425 216 : DO idir = 1, 3
2426 216 : virial_xc(idir, idir) = virial_xc(idir, idir) + tmp
2427 : END DO
2428 :
2429 54 : CALL torch_tensor_release(grid_weight_grad_t)
2430 54 : CALL torch_tensor_release(atomic_grid_weight_grad_t)
2431 :
2432 54 : END SUBROUTINE build_weight_virial
2433 :
2434 : ! **************************************************************************************************
2435 : !> \brief Fill CP2K VXC real-space arrays from Torch feature gradients.
2436 : !> \param vxc_rho ...
2437 : !> \param vxc_tau ...
2438 : !> \param rho_r ...
2439 : !> \param pw_pool ...
2440 : !> \param density_grad ...
2441 : !> \param grad_grad ...
2442 : !> \param kin_grad ...
2443 : !> \param xc_deriv_method_id ...
2444 : !> \param global_grid_layout ...
2445 : ! **************************************************************************************************
2446 326 : SUBROUTINE build_vxc_from_feature_grads(vxc_rho, vxc_tau, rho_r, pw_pool, &
2447 326 : density_grad, grad_grad, kin_grad, &
2448 : xc_deriv_method_id, global_grid_layout)
2449 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: vxc_rho, vxc_tau, rho_r
2450 : TYPE(pw_pool_type), POINTER :: pw_pool
2451 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: density_grad
2452 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: grad_grad
2453 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: kin_grad
2454 : INTEGER, INTENT(IN) :: xc_deriv_method_id
2455 : LOGICAL, INTENT(IN), OPTIONAL :: global_grid_layout
2456 :
2457 : INTEGER :: i, ipt, ispin, j, k, nspins
2458 : INTEGER, DIMENSION(2, 3) :: bo
2459 : LOGICAL :: my_global_grid_layout
2460 : REAL(KIND=dp) :: dvol_inv
2461 : TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
2462 1304 : TYPE(pw_r3d_rs_type), DIMENSION(3) :: grad_pw
2463 :
2464 326 : nspins = SIZE(rho_r)
2465 3260 : bo = rho_r(1)%pw_grid%bounds_local
2466 326 : dvol_inv = 1.0_dp/rho_r(1)%pw_grid%dvol
2467 326 : my_global_grid_layout = .FALSE.
2468 326 : IF (PRESENT(global_grid_layout)) my_global_grid_layout = global_grid_layout
2469 28 : IF (my_global_grid_layout) THEN
2470 112 : CPASSERT(SIZE(density_grad, 1) == PRODUCT(rho_r(1)%pw_grid%npts))
2471 : END IF
2472 :
2473 2052 : ALLOCATE (vxc_rho(nspins), vxc_tau(nspins))
2474 700 : DO ispin = 1, nspins
2475 374 : CALL pw_pool%create_pw(vxc_rho(ispin))
2476 374 : CALL pw_pool%create_pw(vxc_tau(ispin))
2477 374 : CALL pw_zero(vxc_rho(ispin))
2478 700 : CALL pw_zero(vxc_tau(ispin))
2479 : END DO
2480 :
2481 326 : IF (xc_requires_tmp_g(xc_deriv_method_id) .OR. rho_r(1)%pw_grid%spherical) THEN
2482 326 : CALL pw_pool%create_pw(vxc_g)
2483 326 : IF (.NOT. rho_r(1)%pw_grid%spherical) CALL pw_pool%create_pw(tmp_g)
2484 : END IF
2485 :
2486 700 : DO ispin = 1, nspins
2487 1496 : DO i = 1, 3
2488 1122 : CALL pw_pool%create_pw(grad_pw(i))
2489 1496 : CALL pw_zero(grad_pw(i))
2490 : END DO
2491 :
2492 374 : ipt = 0
2493 8212 : DO k = bo(1, 3), bo(2, 3)
2494 201846 : DO j = bo(1, 2), bo(2, 2)
2495 3039443 : DO i = bo(1, 1), bo(2, 1)
2496 2837971 : IF (my_global_grid_layout) THEN
2497 : ipt = 1 + i - rho_r(1)%pw_grid%bounds(1, 1) + &
2498 : rho_r(1)%pw_grid%npts(1)*( &
2499 : j - rho_r(1)%pw_grid%bounds(1, 2) + &
2500 : rho_r(1)%pw_grid%npts(2)*( &
2501 599238 : k - rho_r(1)%pw_grid%bounds(1, 3)))
2502 : ELSE
2503 2238733 : ipt = ipt + 1
2504 : END IF
2505 3031605 : IF (nspins == 1) THEN
2506 : vxc_rho(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2507 2149471 : (density_grad(ipt, 1) + density_grad(ipt, 2))
2508 : vxc_tau(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2509 2149471 : (kin_grad(ipt, 1) + kin_grad(ipt, 2))
2510 : grad_pw(1)%array(i, j, k) = 0.5_dp*dvol_inv* &
2511 2149471 : (grad_grad(ipt, 1, 1) + grad_grad(ipt, 1, 2))
2512 : grad_pw(2)%array(i, j, k) = 0.5_dp*dvol_inv* &
2513 2149471 : (grad_grad(ipt, 2, 1) + grad_grad(ipt, 2, 2))
2514 : grad_pw(3)%array(i, j, k) = 0.5_dp*dvol_inv* &
2515 2149471 : (grad_grad(ipt, 3, 1) + grad_grad(ipt, 3, 2))
2516 : ELSE
2517 688500 : vxc_rho(ispin)%array(i, j, k) = dvol_inv*density_grad(ipt, ispin)
2518 688500 : vxc_tau(ispin)%array(i, j, k) = dvol_inv*kin_grad(ipt, ispin)
2519 688500 : grad_pw(1)%array(i, j, k) = dvol_inv*grad_grad(ipt, 1, ispin)
2520 688500 : grad_pw(2)%array(i, j, k) = dvol_inv*grad_grad(ipt, 2, ispin)
2521 688500 : grad_pw(3)%array(i, j, k) = dvol_inv*grad_grad(ipt, 3, ispin)
2522 : END IF
2523 : END DO
2524 : END DO
2525 : END DO
2526 :
2527 1496 : DO i = 1, 3
2528 1496 : CALL pw_scale(grad_pw(i), -1.0_dp)
2529 : END DO
2530 374 : CALL xc_pw_divergence(xc_deriv_method_id, grad_pw, tmp_g, vxc_g, vxc_rho(ispin))
2531 :
2532 1822 : DO i = 1, 3
2533 1496 : CALL pw_pool%give_back_pw(grad_pw(i))
2534 : END DO
2535 : END DO
2536 :
2537 326 : IF (ASSOCIATED(vxc_g%pw_grid)) CALL pw_pool%give_back_pw(vxc_g)
2538 326 : IF (ASSOCIATED(tmp_g%pw_grid)) CALL pw_pool%give_back_pw(tmp_g)
2539 :
2540 326 : END SUBROUTINE build_vxc_from_feature_grads
2541 :
2542 : ! **************************************************************************************************
2543 : !> \brief Print optional diagnostics for the CP2K-native SKALA GPW feature block.
2544 : !> \param features ...
2545 : !> \param print_active ...
2546 : ! **************************************************************************************************
2547 58 : SUBROUTINE print_native_grid_diagnostics(features, print_active)
2548 : TYPE(skala_gpw_feature_type), INTENT(IN) :: features
2549 : LOGICAL, INTENT(IN) :: print_active
2550 :
2551 : INTEGER :: atom_rows_max, atom_rows_min, &
2552 : chunk_rows_max, chunk_rows_min, iw
2553 : REAL(KIND=dp) :: chunk_imbalance
2554 :
2555 58 : IF (.NOT. print_active) RETURN
2556 :
2557 29 : iw = cp_logger_get_default_io_unit()
2558 29 : IF (iw <= 0) RETURN
2559 : WRITE (UNIT=iw, FMT="(/,T2,A,1X,ES19.11)") &
2560 29 : "SKALA_GPW| Native grid feature electrons", features%electron_count
2561 : WRITE (UNIT=iw, FMT="(T2,A,1X,ES19.11)") &
2562 29 : "SKALA_GPW| Native grid feature spin moment", features%spin_moment
2563 : WRITE (UNIT=iw, FMT="(T2,A,1X,ES19.11)") &
2564 29 : "SKALA_GPW| Native grid feature kinetic integral", features%kinetic_integral
2565 : WRITE (UNIT=iw, FMT="(T2,A,1X,ES19.11)") &
2566 29 : "SKALA_GPW| Native grid feature weight sum", features%grid_weight_sum
2567 29 : IF (ALLOCATED(features%atomic_grid_sizes)) THEN
2568 101 : atom_rows_min = INT(MINVAL(features%atomic_grid_sizes))
2569 101 : atom_rows_max = INT(MAXVAL(features%atomic_grid_sizes))
2570 : WRITE (UNIT=iw, FMT="(T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,I0)") &
2571 29 : "SKALA_GPW| Native grid atom row range", atom_rows_min, "to", &
2572 130 : atom_rows_max, "sum", INT(SUM(features%atomic_grid_sizes))
2573 : END IF
2574 29 : IF (features%uses_atom_chunks) THEN
2575 : WRITE (UNIT=iw, FMT="(T2,A,1X,I0,1X,A,1X,I0)") &
2576 27 : "SKALA_GPW| Native grid atom chunk rows", features%chunk_feature_count, &
2577 54 : "of", features%nflat
2578 27 : IF (ALLOCATED(features%chunk_grad_counts)) THEN
2579 81 : chunk_rows_min = MINVAL(features%chunk_grad_counts)/ngrad_per_point
2580 81 : chunk_rows_max = MAXVAL(features%chunk_grad_counts)/ngrad_per_point
2581 27 : chunk_imbalance = REAL(chunk_rows_max, KIND=dp)/REAL(MAX(1, chunk_rows_min), KIND=dp)
2582 : WRITE (UNIT=iw, FMT="(T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,ES12.5)") &
2583 27 : "SKALA_GPW| Native grid atom chunk row range", chunk_rows_min, &
2584 54 : "to", chunk_rows_max, "imbalance", chunk_imbalance
2585 : END IF
2586 : END IF
2587 :
2588 : END SUBROUTINE print_native_grid_diagnostics
2589 :
2590 : ! **************************************************************************************************
2591 : !> \brief Configure CUDA device selection for the native SKALA GPW Torch path.
2592 : !> \param use_cuda ...
2593 : !> \param requested_device ...
2594 : !> \param group ...
2595 : !> \return selected CUDA device, or -1 for CPU fallback/no visible CUDA device
2596 : ! **************************************************************************************************
2597 386 : FUNCTION configure_native_grid_cuda(use_cuda, requested_device, group) RESULT(selected_device)
2598 : LOGICAL, INTENT(IN) :: use_cuda
2599 : INTEGER, INTENT(IN) :: requested_device
2600 :
2601 : CLASS(mp_comm_type), INTENT(IN) :: group
2602 :
2603 : INTEGER :: cuda_device_count, iw, pe, selected_device
2604 386 : INTEGER, ALLOCATABLE, DIMENSION(:) :: selected_devices
2605 :
2606 386 : selected_device = -1
2607 :
2608 386 : IF (.NOT. use_cuda) RETURN
2609 :
2610 0 : IF (.NOT. torch_cuda_is_available()) THEN
2611 0 : cuda_device_count = 0
2612 : ELSE
2613 0 : cuda_device_count = torch_cuda_device_count()
2614 : END IF
2615 0 : IF (cuda_device_count > 0) THEN
2616 0 : IF (requested_device < 0) THEN
2617 0 : selected_device = MOD(group%mepos, cuda_device_count)
2618 : ELSE
2619 0 : selected_device = requested_device
2620 : END IF
2621 : END IF
2622 0 : IF (selected_device >= cuda_device_count) THEN
2623 : CALL cp_abort(__LOCATION__, &
2624 : "GAUXC%NATIVE_GRID_CUDA_DEVICE selects a CUDA device outside the visible "// &
2625 0 : "Torch CUDA device range.")
2626 : END IF
2627 0 : IF (selected_device >= 0) CALL offload_set_chosen_device(selected_device)
2628 :
2629 0 : ALLOCATE (selected_devices(group%num_pe))
2630 0 : CALL group%allgather(selected_device, selected_devices)
2631 :
2632 0 : IF (group%mepos /= 0) THEN
2633 0 : DEALLOCATE (selected_devices)
2634 0 : RETURN
2635 : END IF
2636 : IF (selected_device == logged_cuda_device .AND. &
2637 : cuda_device_count == logged_cuda_device_count .AND. &
2638 0 : group%num_pe == logged_cuda_nproc .AND. &
2639 : requested_device == logged_cuda_request) THEN
2640 0 : DEALLOCATE (selected_devices)
2641 0 : RETURN
2642 : END IF
2643 :
2644 0 : iw = cp_logger_get_default_io_unit()
2645 0 : IF (iw <= 0) THEN
2646 0 : DEALLOCATE (selected_devices)
2647 0 : RETURN
2648 : END IF
2649 0 : IF (selected_device >= 0) THEN
2650 : WRITE (UNIT=iw, FMT="(/,T2,A,1X,I0,1X,A,1X,I0,1X,A,1X,I0)") &
2651 0 : "SKALA_GPW| Native grid Torch CUDA device", selected_device, &
2652 0 : "of", cuda_device_count, "requested", requested_device
2653 : ELSE
2654 : WRITE (UNIT=iw, FMT="(/,T2,A)") &
2655 0 : "SKALA_GPW| Native grid Torch CUDA requested, but no Torch CUDA device is visible"
2656 : END IF
2657 : WRITE (UNIT=iw, FMT="(T2,A)", ADVANCE="NO") &
2658 0 : "SKALA_GPW| Native grid Torch CUDA rank devices"
2659 0 : DO pe = 1, group%num_pe
2660 0 : WRITE (UNIT=iw, FMT="(1X,I0,A,I0)", ADVANCE="NO") pe - 1, ":", selected_devices(pe)
2661 : END DO
2662 0 : WRITE (UNIT=iw, FMT=*)
2663 :
2664 0 : logged_cuda_device = selected_device
2665 0 : logged_cuda_device_count = cuda_device_count
2666 0 : logged_cuda_nproc = group%num_pe
2667 0 : logged_cuda_request = requested_device
2668 0 : DEALLOCATE (selected_devices)
2669 :
2670 386 : END FUNCTION configure_native_grid_cuda
2671 :
2672 : ! **************************************************************************************************
2673 : !> \brief Load and cache the TorchScript SKALA model.
2674 : !> \param model_path ...
2675 : !> \param cuda_device ...
2676 : ! **************************************************************************************************
2677 384 : SUBROUTINE ensure_model_loaded(model_path, cuda_device)
2678 : CHARACTER(len=*), INTENT(IN) :: model_path
2679 : INTEGER, INTENT(IN) :: cuda_device
2680 :
2681 384 : IF (cached_model_loaded) THEN
2682 287 : IF (TRIM(cached_model_path) == TRIM(model_path) .AND. &
2683 : cached_model_cuda_device == cuda_device) RETURN
2684 0 : CALL skala_torch_model_release(cached_model)
2685 0 : cached_model_loaded = .FALSE.
2686 : END IF
2687 :
2688 97 : CALL skala_torch_model_load(cached_model, TRIM(model_path))
2689 97 : cached_model_path = model_path
2690 97 : cached_model_cuda_device = cuda_device
2691 97 : cached_model_loaded = .TRUE.
2692 :
2693 384 : END SUBROUTINE ensure_model_loaded
2694 :
2695 : ! **************************************************************************************************
2696 : !> \brief Resolve the SKALA TorchScript model path from the GAUXC subsection.
2697 : !> \param xc_section ...
2698 : !> \param model_path ...
2699 : ! **************************************************************************************************
2700 386 : SUBROUTINE get_skala_model_path(xc_section, model_path)
2701 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
2702 : CHARACTER(len=default_path_length), INTENT(OUT) :: model_path
2703 :
2704 : CHARACTER(len=default_path_length) :: model_key
2705 : INTEGER :: env_status
2706 : LOGICAL :: native_grid_use_cuda
2707 : TYPE(section_vals_type), POINTER :: gauxc_section
2708 :
2709 386 : gauxc_section => get_gauxc_section(xc_section)
2710 386 : IF (.NOT. ASSOCIATED(gauxc_section)) THEN
2711 0 : CPABORT("Native SKALA GPW requires an XC_FUNCTIONAL%GAUXC section")
2712 : END IF
2713 :
2714 386 : CALL section_vals_val_get(gauxc_section, "MODEL", c_val=model_path)
2715 386 : model_key = ADJUSTL(model_path)
2716 386 : CALL uppercase(model_key)
2717 386 : IF (TRIM(model_key) == "NONE" .OR. TRIM(model_key) == "") THEN
2718 0 : CPABORT("Native SKALA GPW requires GAUXC%MODEL SKALA or a TorchScript model path")
2719 386 : ELSE IF (TRIM(model_key) == "SKALA") THEN
2720 386 : CALL section_vals_val_get(gauxc_section, "NATIVE_GRID_USE_CUDA", l_val=native_grid_use_cuda)
2721 386 : IF (native_grid_use_cuda) THEN
2722 0 : CALL GET_ENVIRONMENT_VARIABLE("GAUXC_SKALA_CUDA_MODEL", model_path, STATUS=env_status)
2723 0 : IF (env_status == 0 .AND. LEN_TRIM(model_path) > 0) RETURN
2724 : END IF
2725 386 : CALL GET_ENVIRONMENT_VARIABLE("GAUXC_SKALA_MODEL", model_path, STATUS=env_status)
2726 386 : IF (env_status /= 0 .OR. LEN_TRIM(model_path) == 0) THEN
2727 0 : IF (native_grid_use_cuda) THEN
2728 : CALL cp_abort(__LOCATION__, &
2729 0 : "MODEL SKALA CUDA path requires GAUXC_SKALA_CUDA_MODEL or GAUXC_SKALA_MODEL")
2730 : ELSE
2731 : CALL cp_abort(__LOCATION__, &
2732 0 : "MODEL SKALA requires the GAUXC_SKALA_MODEL environment variable")
2733 : END IF
2734 : END IF
2735 : END IF
2736 :
2737 : END SUBROUTINE get_skala_model_path
2738 :
2739 : ! **************************************************************************************************
2740 : !> \brief Return the first GAUXC functional subsection, if present.
2741 : !> \param xc_section ...
2742 : !> \return ...
2743 : ! **************************************************************************************************
2744 681166 : FUNCTION get_gauxc_section(xc_section) RESULT(gauxc_section)
2745 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
2746 : TYPE(section_vals_type), POINTER :: gauxc_section
2747 :
2748 : INTEGER :: ifun
2749 : TYPE(section_vals_type), POINTER :: functionals, xc_fun
2750 :
2751 681166 : NULLIFY (gauxc_section)
2752 681166 : IF (.NOT. ASSOCIATED(xc_section)) RETURN
2753 :
2754 681166 : functionals => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
2755 681166 : IF (.NOT. ASSOCIATED(functionals)) RETURN
2756 :
2757 681166 : ifun = 0
2758 : DO
2759 1315932 : ifun = ifun + 1
2760 1315932 : xc_fun => section_vals_get_subs_vals2(functionals, i_section=ifun)
2761 1315932 : IF (.NOT. ASSOCIATED(xc_fun)) EXIT
2762 1315932 : IF (xc_fun%section%name == "GAUXC") THEN
2763 : gauxc_section => xc_fun
2764 : EXIT
2765 : END IF
2766 : END DO
2767 :
2768 : END FUNCTION get_gauxc_section
2769 :
2770 0 : END MODULE skala_gpw_functional
|