29#include "./base/base_uses.f90"
38 REAL(KIND=
dp),
PRIVATE,
PARAMETER :: default_verlet_skin = 0.5_dp
39 REAL(KIND=
dp),
PRIVATE,
PARAMETER :: rebuild_eps = 1.0e-12_dp
57 TYPE(
nnp_type),
INTENT(INOUT),
POINTER :: nnp
61 REAL(kind=
dp) :: dr2_max, exact_cutoff, list_cutoff, skin
62 REAL(kind=
dp),
DIMENSION(3) :: dr
65 CALL timeset(
'nnp_acsf_cell_list_prepare', handle)
70 exact_cutoff = nnp%max_cut
71 IF (exact_cutoff > 0.0_dp)
THEN
72 IF (nnp%verlet_skin >= 0.0_dp)
THEN
74 skin = nnp%verlet_skin
77 skin = min(default_verlet_skin, 0.1_dp*exact_cutoff)
82 list_cutoff = exact_cutoff + skin
84 CALL nnp_cell_list_ensure_coord_buffers(nnp%cell_list_cache, nnp%num_atoms)
86 associate(cache => nnp%cell_list_cache)
87 DO i = 1, nnp%num_atoms
88 cache%coord_primary(:, i) =
pbc(nnp%coord(:, i), cell, .true.)
90 cache%coord_primary(:, i), cell)
93 rebuild = .NOT. cache%initialized
94 IF (.NOT. rebuild) rebuild = (cache%num_atoms /= nnp%num_atoms)
95 IF (.NOT. rebuild) rebuild = (abs(cache%exact_cutoff - exact_cutoff) > rebuild_eps)
96 IF (.NOT. rebuild) rebuild = (abs(cache%list_cutoff - list_cutoff) > rebuild_eps)
97 IF (.NOT. rebuild) rebuild = (abs(cache%verlet_skin - skin) > rebuild_eps)
98 IF (.NOT. rebuild) rebuild = any(cache%perd /= cell%perd)
99 IF (.NOT. rebuild) rebuild = (cache%orthorhombic .NEQV. cell%orthorhombic)
100 IF (.NOT. rebuild) rebuild = any(abs(cache%hmat - cell%hmat) > rebuild_eps)
101 IF (.NOT. rebuild) rebuild = any(abs(cache%h_inv - cell%h_inv) > rebuild_eps)
103 IF ((.NOT. rebuild) .AND. (skin > 0.0_dp))
THEN
105 DO i = 1, nnp%num_atoms
106 dr(:) = cache%coord_primary(:, i) - cache%ref_coord_primary(:, i)
107 dr(:) =
pbc(dr, cell)
108 dr2_max = max(dr2_max, dot_product(dr, dr))
110 IF (dr2_max > 0.25_dp*skin**2) rebuild = .true.
114 CALL nnp_build_cell_list_cache(cache, cell, exact_cutoff, list_cutoff, skin)
115 ELSE IF (cache%initialized)
THEN
119 CALL nnp_cell_list_rebin_chain(cache)
123 CALL timestop(handle)
133 SUBROUTINE nnp_cell_list_ensure_coord_buffers(cache, num_atoms)
135 TYPE(nnp_cell_list_cache_type),
INTENT(INOUT) :: cache
136 INTEGER,
INTENT(IN) :: num_atoms
138 IF (
ALLOCATED(cache%coord_primary))
THEN
139 IF (
SIZE(cache%coord_primary, 2) == num_atoms)
RETURN
140 DEALLOCATE (cache%coord_primary)
142 IF (
ALLOCATED(cache%coord_scaled))
DEALLOCATE (cache%coord_scaled)
143 IF (
ALLOCATED(cache%ref_coord_primary))
DEALLOCATE (cache%ref_coord_primary)
145 ALLOCATE (cache%coord_primary(3, num_atoms))
146 ALLOCATE (cache%coord_scaled(3, num_atoms))
147 ALLOCATE (cache%ref_coord_primary(3, num_atoms))
150 cache%initialized = .false.
151 cache%num_atoms = num_atoms
153 END SUBROUTINE nnp_cell_list_ensure_coord_buffers
167 SUBROUTINE nnp_build_cell_list_cache(cache, cell, exact_cutoff, list_cutoff, skin)
169 TYPE(nnp_cell_list_cache_type),
INTENT(INOUT) :: cache
170 TYPE(cell_type),
INTENT(IN),
POINTER :: cell
171 REAL(kind=dp),
INTENT(IN) :: exact_cutoff, list_cutoff, skin
173 INTEGER :: i, img, n_images, nx, ny, nz, tx, ty, tz
174 INTEGER,
DIMENSION(3) :: bin_index, shift
175 REAL(kind=dp) :: padding, safe_cutoff
176 REAL(kind=dp),
DIMENSION(3) :: max_ref, min_ref, range_xyz, ref_pos
178 CALL nnp_cell_list_release_cell_structure(cache)
180 cache%exact_cutoff = exact_cutoff
181 cache%list_cutoff = list_cutoff
182 cache%verlet_skin = skin
183 cache%perd = cell%perd
184 cache%orthorhombic = cell%orthorhombic
185 cache%hmat = cell%hmat
186 cache%h_inv = cell%h_inv
188 cache%ref_coord_primary(:, :) = cache%coord_primary(:, :)
190 CALL nnp_compute_pbc_copies(cache%exact_pbc_copies, cell, exact_cutoff)
191 CALL nnp_compute_pbc_copies(cache%list_pbc_copies, cell, list_cutoff)
196 cache%image_copies = max(cache%list_pbc_copies, cell%perd)
199 cpassert(all(cache%exact_pbc_copies <= cache%image_copies))
201 nx = 2*cache%image_copies(1) + 1
202 ny = 2*cache%image_copies(2) + 1
203 nz = 2*cache%image_copies(3) + 1
204 n_images = cache%num_atoms*nx*ny*nz
205 cache%n_images = n_images
207 ALLOCATE (cache%image_atom(n_images))
208 ALLOCATE (cache%image_shift(3, n_images))
209 ALLOCATE (cache%image_translation(3, n_images))
211 min_ref(:) = huge(1.0_dp)
212 max_ref(:) = -huge(1.0_dp)
214 DO i = 1, cache%num_atoms
215 DO tx = -cache%image_copies(1), cache%image_copies(1)
216 DO ty = -cache%image_copies(2), cache%image_copies(2)
217 DO tz = -cache%image_copies(3), cache%image_copies(3)
220 cache%image_atom(img) = i
221 cache%image_shift(:, img) = shift(:)
222 cache%image_translation(:, img) = matmul(cell%hmat, real(shift, kind=dp))
223 ref_pos(:) = cache%coord_primary(:, i) + cache%image_translation(:, img)
224 min_ref(:) = min(min_ref(:), ref_pos(:))
225 max_ref(:) = max(max_ref(:), ref_pos(:))
231 padding = 0.5_dp*skin + rebuild_eps
232 cache%lower(:) = min_ref(:) - padding
233 cache%upper(:) = max_ref(:) + padding
234 range_xyz(:) = cache%upper(:) - cache%lower(:)
239 safe_cutoff = max(list_cutoff, rebuild_eps)
241 IF (range_xyz(i) > rebuild_eps)
THEN
242 cache%nbin(i) = max(1, ceiling(range_xyz(i)/safe_cutoff))
243 cache%bin_width(i) = range_xyz(i)/real(cache%nbin(i), kind=dp)
244 cache%bin_span(i) = min(cache%nbin(i) - 1, &
245 ceiling(list_cutoff/max(cache%bin_width(i), rebuild_eps)))
248 cache%bin_width(i) = 1.0_dp
249 cache%bin_span(i) = 0
253 cache%n_cells = product(cache%nbin)
254 ALLOCATE (cache%head(cache%n_cells))
255 ALLOCATE (cache%next(n_images))
260 i = cache%image_atom(img)
261 ref_pos(:) = cache%coord_primary(:, i) + cache%image_translation(:, img)
262 CALL nnp_cell_list_bin_from_position(cache, ref_pos, bin_index)
263 cache%next(img) = cache%head(nnp_cell_list_linear_index(cache, bin_index))
264 cache%head(nnp_cell_list_linear_index(cache, bin_index)) = img
267 cache%initialized = .true.
269 END SUBROUTINE nnp_build_cell_list_cache
277 SUBROUTINE nnp_cell_list_rebin_chain(cache)
279 TYPE(nnp_cell_list_cache_type),
INTENT(INOUT) :: cache
281 INTEGER :: i, img, lin_idx
282 INTEGER,
DIMENSION(3) :: bin_index
283 REAL(kind=dp),
DIMENSION(3) :: ref_pos
288 DO img = 1, cache%n_images
289 i = cache%image_atom(img)
290 ref_pos(:) = cache%coord_primary(:, i) + cache%image_translation(:, img)
291 CALL nnp_cell_list_bin_from_position(cache, ref_pos, bin_index)
292 lin_idx = nnp_cell_list_linear_index(cache, bin_index)
293 cache%next(img) = cache%head(lin_idx)
294 cache%head(lin_idx) = img
297 END SUBROUTINE nnp_cell_list_rebin_chain
305 SUBROUTINE nnp_cell_list_release_cell_structure(cache)
307 TYPE(nnp_cell_list_cache_type),
INTENT(INOUT) :: cache
309 IF (
ALLOCATED(cache%image_atom))
DEALLOCATE (cache%image_atom)
310 IF (
ALLOCATED(cache%head))
DEALLOCATE (cache%head)
311 IF (
ALLOCATED(cache%next))
DEALLOCATE (cache%next)
312 IF (
ALLOCATED(cache%image_shift))
DEALLOCATE (cache%image_shift)
313 IF (
ALLOCATED(cache%image_translation))
DEALLOCATE (cache%image_translation)
317 cache%exact_pbc_copies = 0
318 cache%list_pbc_copies = 0
319 cache%image_copies = 0
324 cache%bin_width = 1.0_dp
326 END SUBROUTINE nnp_cell_list_release_cell_structure
341 TYPE(nnp_type),
INTENT(INOUT),
POINTER :: nnp
342 TYPE(nnp_neighbor_type),
INTENT(INOUT) :: neighbor
343 INTEGER,
INTENT(IN) :: i
345 INTEGER :: bx, by, bz, img, ind, j, neighbor_ind, &
347 INTEGER,
DIMENSION(3) :: bin_index, current_shift
348 REAL(kind=dp) :: norm
349 REAL(kind=dp),
DIMENSION(3) :: center, dr, image_pos
351 associate(cache => nnp%cell_list_cache, &
352 state => nnp%neighbor_interface_state)
355 center(:) = cache%coord_primary(:, i)
356 CALL nnp_cell_list_bin_from_position(cache, center, bin_index)
358 DO bx = max(1, bin_index(1) - cache%bin_span(1)), &
359 min(cache%nbin(1), bin_index(1) + cache%bin_span(1))
360 DO by = max(1, bin_index(2) - cache%bin_span(2)), &
361 min(cache%nbin(2), bin_index(2) + cache%bin_span(2))
362 DO bz = max(1, bin_index(3) - cache%bin_span(3)), &
363 min(cache%nbin(3), bin_index(3) + cache%bin_span(3))
364 img = cache%head(nnp_cell_list_linear_index(cache, [bx, by, bz]))
366 j = cache%image_atom(img)
367 current_shift(:) = cache%image_shift(:, img)
368 IF (j == i .AND. all(current_shift == 0))
THEN
369 img = cache%next(img)
372 IF (.NOT. nnp_cell_list_exact_image_match(cache, i, j, current_shift))
THEN
373 img = cache%next(img)
377 image_pos(:) = cache%coord_primary(:, j) + cache%image_translation(:, img)
378 dr(:) = center(:) - image_pos(:)
380 neighbor_ind = nnp%ele_ind(j)
382 IF (norm < state%pair_map(ind, neighbor_ind)%max_relevant_cutoff)
THEN
383 DO pair_slot = 1, state%pair_map(ind, neighbor_ind)%n_rad
384 s = state%pair_map(ind, neighbor_ind)%rad_groups(pair_slot)
385 IF (norm < nnp%rad(ind)%symfgrp(s)%cutoff)
THEN
386 neighbor%n_rad(s) = neighbor%n_rad(s) + 1
387 IF (neighbor%n_rad(s) > neighbor%rad(s)%cap)
THEN
388 CALL nnp_neigh_grp_grow(neighbor%rad(s), neighbor%n_rad(s))
390 neighbor%rad(s)%ind(neighbor%n_rad(s)) = j
391 neighbor%rad(s)%dist(1, neighbor%n_rad(s)) = dr(1)
392 neighbor%rad(s)%dist(2, neighbor%n_rad(s)) = dr(2)
393 neighbor%rad(s)%dist(3, neighbor%n_rad(s)) = dr(3)
394 neighbor%rad(s)%dist(4, neighbor%n_rad(s)) = norm
398 DO pair_slot = 1, state%pair_map(ind, neighbor_ind)%n_ang1
399 s = state%pair_map(ind, neighbor_ind)%ang1_groups(pair_slot)
400 IF (norm < nnp%ang(ind)%symfgrp(s)%cutoff)
THEN
401 neighbor%n_ang1(s) = neighbor%n_ang1(s) + 1
402 IF (neighbor%n_ang1(s) > neighbor%ang1(s)%cap)
THEN
403 CALL nnp_neigh_grp_grow(neighbor%ang1(s), neighbor%n_ang1(s))
405 neighbor%ang1(s)%ind(neighbor%n_ang1(s)) = j
406 neighbor%ang1(s)%dist(1, neighbor%n_ang1(s)) = dr(1)
407 neighbor%ang1(s)%dist(2, neighbor%n_ang1(s)) = dr(2)
408 neighbor%ang1(s)%dist(3, neighbor%n_ang1(s)) = dr(3)
409 neighbor%ang1(s)%dist(4, neighbor%n_ang1(s)) = norm
413 DO pair_slot = 1, state%pair_map(ind, neighbor_ind)%n_ang2
414 s = state%pair_map(ind, neighbor_ind)%ang2_groups(pair_slot)
415 IF (norm < nnp%ang(ind)%symfgrp(s)%cutoff)
THEN
416 neighbor%n_ang2(s) = neighbor%n_ang2(s) + 1
417 IF (neighbor%n_ang2(s) > neighbor%ang2(s)%cap)
THEN
418 CALL nnp_neigh_grp_grow(neighbor%ang2(s), neighbor%n_ang2(s))
420 neighbor%ang2(s)%ind(neighbor%n_ang2(s)) = j
421 neighbor%ang2(s)%dist(1, neighbor%n_ang2(s)) = dr(1)
422 neighbor%ang2(s)%dist(2, neighbor%n_ang2(s)) = dr(2)
423 neighbor%ang2(s)%dist(3, neighbor%n_ang2(s)) = dr(3)
424 neighbor%ang2(s)%dist(4, neighbor%n_ang2(s)) = norm
429 img = cache%next(img)
447 LOGICAL FUNCTION nnp_cell_list_exact_image_match(cache, i, j, image_shift)
449 TYPE(nnp_cell_list_cache_type),
INTENT(IN) :: cache
450 INTEGER,
INTENT(IN) :: i, j
451 INTEGER,
DIMENSION(3),
INTENT(IN) :: image_shift
453 INTEGER :: d, minimal_shift
455 nnp_cell_list_exact_image_match = .true.
457 IF (cache%perd(d) == 1)
THEN
458 minimal_shift = nint(cache%coord_scaled(d, i) - cache%coord_scaled(d, j))
459 IF (abs(minimal_shift - image_shift(d)) > cache%exact_pbc_copies(d))
THEN
460 nnp_cell_list_exact_image_match = .false.
463 ELSE IF (image_shift(d) /= 0)
THEN
464 nnp_cell_list_exact_image_match = .false.
469 END FUNCTION nnp_cell_list_exact_image_match
477 SUBROUTINE nnp_cell_list_bin_from_position(cache, pos, bin_index)
479 TYPE(nnp_cell_list_cache_type),
INTENT(IN) :: cache
480 REAL(kind=dp),
DIMENSION(3),
INTENT(IN) :: pos
481 INTEGER,
DIMENSION(3),
INTENT(OUT) :: bin_index
484 REAL(kind=dp) :: scaled
487 scaled = (pos(d) - cache%lower(d))/max(cache%bin_width(d), rebuild_eps)
488 bin_index(d) = int(scaled) + 1
489 bin_index(d) = max(1, min(cache%nbin(d), bin_index(d)))
492 END SUBROUTINE nnp_cell_list_bin_from_position
500 INTEGER FUNCTION nnp_cell_list_linear_index(cache, bin_index)
502 TYPE(nnp_cell_list_cache_type),
INTENT(IN) :: cache
503 INTEGER,
DIMENSION(3),
INTENT(IN) :: bin_index
505 nnp_cell_list_linear_index = bin_index(1) + cache%nbin(1)* &
506 ((bin_index(2) - 1) + cache%nbin(2)*(bin_index(3) - 1))
508 END FUNCTION nnp_cell_list_linear_index
520 SUBROUTINE nnp_compute_pbc_copies(pbc_copies, cell, cutoff)
522 INTEGER,
DIMENSION(3),
INTENT(OUT) :: pbc_copies
523 TYPE(cell_type),
INTENT(IN),
POINTER :: cell
524 REAL(kind=dp),
INTENT(IN) :: cutoff
526 REAL(kind=dp) :: proja, projb, projc
527 REAL(kind=dp),
DIMENSION(3) :: axb, axc, bxc
531 cpassert(cell%deth > 0.0_dp)
533 axb(1) = cell%hmat(2, 1)*cell%hmat(3, 2) - cell%hmat(3, 1)*cell%hmat(2, 2)
534 axb(2) = cell%hmat(3, 1)*cell%hmat(1, 2) - cell%hmat(1, 1)*cell%hmat(3, 2)
535 axb(3) = cell%hmat(1, 1)*cell%hmat(2, 2) - cell%hmat(2, 1)*cell%hmat(1, 2)
536 axb(:) = axb(:)/norm2(axb(:))
538 axc(1) = cell%hmat(2, 1)*cell%hmat(3, 3) - cell%hmat(3, 1)*cell%hmat(2, 3)
539 axc(2) = cell%hmat(3, 1)*cell%hmat(1, 3) - cell%hmat(1, 1)*cell%hmat(3, 3)
540 axc(3) = cell%hmat(1, 1)*cell%hmat(2, 3) - cell%hmat(2, 1)*cell%hmat(1, 3)
541 axc(:) = axc(:)/norm2(axc(:))
543 bxc(1) = cell%hmat(2, 2)*cell%hmat(3, 3) - cell%hmat(3, 2)*cell%hmat(2, 3)
544 bxc(2) = cell%hmat(3, 2)*cell%hmat(1, 3) - cell%hmat(1, 2)*cell%hmat(3, 3)
545 bxc(3) = cell%hmat(1, 2)*cell%hmat(2, 3) - cell%hmat(2, 2)*cell%hmat(1, 3)
546 bxc(:) = bxc(:)/norm2(bxc(:))
548 proja = abs(sum(cell%hmat(:, 1)*bxc(:)))*0.5_dp
549 projb = abs(sum(cell%hmat(:, 2)*axc(:)))*0.5_dp
550 projc = abs(sum(cell%hmat(:, 3)*axb(:)))*0.5_dp
553 DO WHILE ((pbc_copies(1) + 1)*proja <= cutoff)
554 pbc_copies(1) = pbc_copies(1) + 1
556 DO WHILE ((pbc_copies(2) + 1)*projb <= cutoff)
557 pbc_copies(2) = pbc_copies(2) + 1
559 DO WHILE ((pbc_copies(3) + 1)*projc <= cutoff)
560 pbc_copies(3) = pbc_copies(3) + 1
562 pbc_copies(:) = pbc_copies(:)*cell%perd(:)
564 END SUBROUTINE nnp_compute_pbc_copies
Handles all functions related to the CELL.
subroutine, public real_to_scaled(s, r, cell)
Transform real to scaled cell coordinates. s=h_inv*r.
Defines the basic variable types.
integer, parameter, public dp
Linked-cell neighbour finder with a Verlet skin for the NNP descriptor. Owns the per-nnp cell-list ca...
subroutine, public nnp_prepare_cell_list_cache(nnp)
Prepare the cell-list cache for the current force evaluation: wrap positions into the primary cell,...
subroutine, public nnp_compute_neighbors_cell_list(nnp, neighbor, i)
Fill the ACSF neighbour buffers for one central atom by walking the linked-cell stencil around its bi...
Data types for neural network potentials.
subroutine, public nnp_env_get(nnp_env, nnp_forces, subsys, atomic_kind_set, particle_set, local_particles, molecule_kind_set, molecule_set, local_molecules, nnp_input, force_env_input, cell, cell_ref, use_ref_cell, nnp_potential_energy, virial)
Returns various attributes of the nnp environment.
Per-nnp persistent neighbour-interface state for the NNP hot path. Separates neighbour bookkeeping fr...
subroutine, public nnp_neigh_grp_grow(grp, n_needed)
Ensure a per-group (ind, dist) neighbour buffer holds n_needed entries. Called from inside the linked...
Type defining parameters related to the simulation cell.
Linked-cell + Verlet-skin cache for the NNP descriptor neighbour walk. Persisted across MD steps so t...
Contains neighbors list of an atom (per-group dense layout).
Main data type collecting all relevant data for neural network potentials.