(git:f2099e5)
Loading...
Searching...
No Matches
nnp_neighbor_interface.F
Go to the documentation of this file.
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 Per-nnp persistent neighbour-interface state for the NNP hot path.
10!> Separates neighbour bookkeeping from the ACSF and network loops:
11!> species-pair routing is precomputed once and per-element work
12!> buffers are reused. State lives on the parent nnp_type, so each
13!> &NNP force_eval keeps its own copy and the lifetime tracks
14!> nnp_env_release.
15!> \author Dhruv Sharma (ds2173@cam.ac.uk)
16!> \author Christoph Schran (christoph.schran@rub.de)
17!> \date 2026-05-21
18! **************************************************************************************************
20
21 USE kinds, ONLY: dp
27
28!$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
29#include "./base/base_uses.f90"
30
31 IMPLICIT NONE
32
33 PRIVATE
34
40
41CONTAINS
42
43! **************************************************************************************************
44!> \brief Ensure pair-routing metadata and reusable workspaces are ready for the current NNP model.
45!> \param nnp NNP environment whose neighbor_interface_state will be (re)built if needed.
46!> \author Dhruv Sharma (ds2173@cam.ac.uk)
47! **************************************************************************************************
49
50 TYPE(nnp_type), INTENT(INOUT) :: nnp
51
52 CHARACTER(len=*), PARAMETER :: routinen = 'nnp_neighbor_interface_prepare'
53
54 INTEGER :: handle
55 LOGICAL :: rebuild
56
57 CALL timeset(routinen, handle)
58
59 rebuild = .NOT. nnp%neighbor_interface_state%initialized
60 IF (.NOT. rebuild) CALL nnp_neighbor_interface_needs_rebuild(nnp, rebuild)
61
62 IF (rebuild) THEN
63 CALL nnp_neighbor_interface_state_release(nnp%neighbor_interface_state)
64 CALL nnp_neighbor_interface_build_pair_maps(nnp)
65 END IF
66
67 CALL timestop(handle)
68
70
71! **************************************************************************************************
72!> \brief Reset per-group neighbour counters for one central element before refilling
73!> the reusable buffers. Zeroes n_rad/n_ang1/n_ang2; the (ind, dist) slabs
74!> are kept allocated and overwritten in place by the next push.
75!> \param nnp NNP environment whose neighbor_interface_state will have its counters cleared.
76!> \param ind central-element index (1..nnp%n_ele) whose workspace is reset.
77!> \author Dhruv Sharma (ds2173@cam.ac.uk)
78! **************************************************************************************************
80
81 TYPE(nnp_type), INTENT(INOUT) :: nnp
82 INTEGER, INTENT(IN) :: ind
83
84 INTEGER :: tid
85
86 tid = 1
87!$ tid = omp_get_thread_num() + 1
88 nnp%neighbor_interface_state%workspace(ind, tid)%neighbor%n_rad(:) = 0
89 nnp%neighbor_interface_state%workspace(ind, tid)%neighbor%n_ang1(:) = 0
90 nnp%neighbor_interface_state%workspace(ind, tid)%neighbor%n_ang2(:) = 0
91
93
94! **************************************************************************************************
95!> \brief Check whether the persistent state matches the current NNP model. Assumes
96!> the per-group routing (ele_ind, cutoff) is fixed after nnp_init_acsf_groups,
97!> so only element and per-element group counts are compared.
98!> \param nnp NNP environment whose persistent neighbour-interface state will be inspected
99!> \param rebuild (out) .TRUE. if element count or per-element group sizes have changed
100! **************************************************************************************************
101 SUBROUTINE nnp_neighbor_interface_needs_rebuild(nnp, rebuild)
102
103 TYPE(nnp_type), INTENT(IN) :: nnp
104 LOGICAL, INTENT(OUT) :: rebuild
105
106 INTEGER :: i
107
108 rebuild = .false.
109 IF (nnp%neighbor_interface_state%n_ele /= nnp%n_ele) THEN
110 rebuild = .true.
111 RETURN
112 END IF
113 IF (.NOT. ALLOCATED(nnp%neighbor_interface_state%n_rad)) THEN
114 rebuild = .true.
115 RETURN
116 END IF
117
118 DO i = 1, nnp%n_ele
119 IF (nnp%neighbor_interface_state%n_rad(i) /= nnp%n_rad(i) .OR. &
120 nnp%neighbor_interface_state%n_ang(i) /= nnp%n_ang(i) .OR. &
121 nnp%neighbor_interface_state%n_radgrp(i) /= nnp%rad(i)%n_symfgrp .OR. &
122 nnp%neighbor_interface_state%n_anggrp(i) /= nnp%ang(i)%n_symfgrp) THEN
123 rebuild = .true.
124 RETURN
125 END IF
126 END DO
127
128 END SUBROUTINE nnp_neighbor_interface_needs_rebuild
129
130! **************************************************************************************************
131!> \brief Build species-pair routing tables and initialize reusable workspaces.
132!> \param nnp NNP environment; pair_map and workspace arrays are (re-)allocated on its neighbor_interface_state
133! **************************************************************************************************
134 SUBROUTINE nnp_neighbor_interface_build_pair_maps(nnp)
135
136 TYPE(nnp_type), INTENT(INOUT) :: nnp
137
138 INTEGER :: i, nthreads, t
139
140 associate(state => nnp%neighbor_interface_state)
141 state%n_ele = nnp%n_ele
142 ALLOCATE (state%n_rad(nnp%n_ele))
143 ALLOCATE (state%n_ang(nnp%n_ele))
144 ALLOCATE (state%n_radgrp(nnp%n_ele))
145 ALLOCATE (state%n_anggrp(nnp%n_ele))
146 ALLOCATE (state%pair_map(nnp%n_ele, nnp%n_ele))
147 ! one workspace column per thread of the atom loop in nnp_calc_energy_force
148 nthreads = 1
149!$ nthreads = omp_get_max_threads()
150 ALLOCATE (state%workspace(nnp%n_ele, nthreads))
151
152 DO i = 1, nnp%n_ele
153 state%n_rad(i) = nnp%n_rad(i)
154 state%n_ang(i) = nnp%n_ang(i)
155 state%n_radgrp(i) = nnp%rad(i)%n_symfgrp
156 state%n_anggrp(i) = nnp%ang(i)%n_symfgrp
157 END DO
158
159 DO i = 1, nnp%n_ele
160 CALL nnp_neighbor_interface_build_pair_map_for_element(nnp, i)
161 DO t = 1, nthreads
162 CALL nnp_neighbor_interface_init_workspace_metadata(nnp, i, t)
163 END DO
164 END DO
165
166 state%initialized = .true.
167 END associate
168
169 END SUBROUTINE nnp_neighbor_interface_build_pair_maps
170
171! **************************************************************************************************
172!> \brief Build all species-pair routes for one central element.
173!> \param nnp NNP environment providing the radial/angular SF groups
174!> \param ind central-element index whose pair-map row is built
175! **************************************************************************************************
176 SUBROUTINE nnp_neighbor_interface_build_pair_map_for_element(nnp, ind)
177
178 TYPE(nnp_type), INTENT(INOUT) :: nnp
179 INTEGER, INTENT(IN) :: ind
180
181 INTEGER :: idx, neighbor_ind, s
182
183 DO neighbor_ind = 1, nnp%n_ele
184 associate(pair_map => nnp%neighbor_interface_state%pair_map(ind, neighbor_ind))
185 pair_map%n_rad = 0
186 pair_map%n_ang1 = 0
187 pair_map%n_ang2 = 0
188 pair_map%max_relevant_cutoff = 0.0_dp
189
190 DO s = 1, nnp%rad(ind)%n_symfgrp
191 IF (nnp%rad(ind)%symfgrp(s)%ele_ind(1) == neighbor_ind) pair_map%n_rad = pair_map%n_rad + 1
192 END DO
193 DO s = 1, nnp%ang(ind)%n_symfgrp
194 IF (nnp%ang(ind)%symfgrp(s)%ele_ind(1) == neighbor_ind) pair_map%n_ang1 = pair_map%n_ang1 + 1
195 IF (nnp%ang(ind)%symfgrp(s)%ele_ind(2) == neighbor_ind) pair_map%n_ang2 = pair_map%n_ang2 + 1
196 END DO
197
198 ALLOCATE (pair_map%rad_groups(max(1, pair_map%n_rad)))
199 ALLOCATE (pair_map%ang1_groups(max(1, pair_map%n_ang1)))
200 ALLOCATE (pair_map%ang2_groups(max(1, pair_map%n_ang2)))
201
202 idx = 0
203 DO s = 1, nnp%rad(ind)%n_symfgrp
204 IF (nnp%rad(ind)%symfgrp(s)%ele_ind(1) == neighbor_ind) THEN
205 idx = idx + 1
206 pair_map%rad_groups(idx) = s
207 pair_map%max_relevant_cutoff = max(pair_map%max_relevant_cutoff, nnp%rad(ind)%symfgrp(s)%cutoff)
208 END IF
209 END DO
210
211 idx = 0
212 DO s = 1, nnp%ang(ind)%n_symfgrp
213 IF (nnp%ang(ind)%symfgrp(s)%ele_ind(1) == neighbor_ind) THEN
214 idx = idx + 1
215 pair_map%ang1_groups(idx) = s
216 pair_map%max_relevant_cutoff = max(pair_map%max_relevant_cutoff, nnp%ang(ind)%symfgrp(s)%cutoff)
217 END IF
218 END DO
219
220 idx = 0
221 DO s = 1, nnp%ang(ind)%n_symfgrp
222 IF (nnp%ang(ind)%symfgrp(s)%ele_ind(2) == neighbor_ind) THEN
223 idx = idx + 1
224 pair_map%ang2_groups(idx) = s
225 pair_map%max_relevant_cutoff = max(pair_map%max_relevant_cutoff, nnp%ang(ind)%symfgrp(s)%cutoff)
226 END IF
227 END DO
228 END associate
229 END DO
230
231 END SUBROUTINE nnp_neighbor_interface_build_pair_map_for_element
232
233! **************************************************************************************************
234!> \brief Cache max scratch sizes for one central element.
235!> \param nnp NNP environment providing per-element SF group definitions
236!> \param ind central-element index whose scratch workspace metadata is cached
237!> \param tid thread index whose workspace column is initialised
238! **************************************************************************************************
239 SUBROUTINE nnp_neighbor_interface_init_workspace_metadata(nnp, ind, tid)
240
241 TYPE(nnp_type), INTENT(INOUT) :: nnp
242 INTEGER, INTENT(IN) :: ind, tid
243
244 INTEGER :: s
245
246 associate(workspace => nnp%neighbor_interface_state%workspace(ind, tid))
247 workspace%max_rad_symf = 0
248 workspace%max_ang_symf = 0
249 workspace%n_input_nodes = nnp%n_rad(ind) + nnp%n_ang(ind)
250
251 DO s = 1, nnp%rad(ind)%n_symfgrp
252 workspace%max_rad_symf = max(workspace%max_rad_symf, nnp%rad(ind)%symfgrp(s)%n_symf)
253 END DO
254 DO s = 1, nnp%ang(ind)%n_symfgrp
255 workspace%max_ang_symf = max(workspace%max_ang_symf, nnp%ang(ind)%symfgrp(s)%n_symf)
256 END DO
257
258 ! Per-SF scratch reused inside nnp_calc_rad / nnp_calc_ang, sized by max_*_symf.
259 IF (ALLOCATED(workspace%radial_sym)) DEALLOCATE (workspace%radial_sym)
260 IF (ALLOCATED(workspace%radial_force)) DEALLOCATE (workspace%radial_force)
261 IF (ALLOCATED(workspace%angular_sym)) DEALLOCATE (workspace%angular_sym)
262 IF (ALLOCATED(workspace%angular_force)) DEALLOCATE (workspace%angular_force)
263 ALLOCATE (workspace%radial_sym(max(1, workspace%max_rad_symf)))
264 ALLOCATE (workspace%radial_force(3, max(1, workspace%max_rad_symf)))
265 ALLOCATE (workspace%angular_sym(max(1, workspace%max_ang_symf)))
266 ALLOCATE (workspace%angular_force(3, 3, max(1, workspace%max_ang_symf)))
267
268 ! 1D angular cutoff caches; start small and grow lazily to the peak
269 ! per-element angular neighbour count (nnp_workspace_grow_caches).
270 IF (ALLOCATED(workspace%fc_cache1)) DEALLOCATE (workspace%fc_cache1)
271 IF (ALLOCATED(workspace%dfc_cache1)) DEALLOCATE (workspace%dfc_cache1)
272 IF (ALLOCATED(workspace%fc_cache2)) DEALLOCATE (workspace%fc_cache2)
273 IF (ALLOCATED(workspace%dfc_cache2)) DEALLOCATE (workspace%dfc_cache2)
274 workspace%cache_cap = 8
275 ALLOCATE (workspace%fc_cache1(workspace%cache_cap))
276 ALLOCATE (workspace%dfc_cache1(workspace%cache_cap))
277 ALLOCATE (workspace%fc_cache2(workspace%cache_cap))
278 ALLOCATE (workspace%dfc_cache2(workspace%cache_cap))
279
280 ! self_dGdr sized once here; independent of the candidate pool.
281 IF (ALLOCATED(workspace%self_dGdr)) DEALLOCATE (workspace%self_dGdr)
282 ALLOCATE (workspace%self_dGdr(3, max(1, workspace%n_input_nodes)))
283
284 ! Per-group neighbour counters and dense (ind, dist) containers, sized to
285 ! n_symfgrp here; the per-group slabs grow lazily via nnp_neigh_grp_grow.
286 CALL nnp_release_neighbor_local(workspace)
287 ALLOCATE (workspace%neighbor%n_rad(max(1, nnp%rad(ind)%n_symfgrp)))
288 ALLOCATE (workspace%neighbor%n_ang1(max(1, nnp%ang(ind)%n_symfgrp)))
289 ALLOCATE (workspace%neighbor%n_ang2(max(1, nnp%ang(ind)%n_symfgrp)))
290 ALLOCATE (workspace%neighbor%rad(max(1, nnp%rad(ind)%n_symfgrp)))
291 ALLOCATE (workspace%neighbor%ang1(max(1, nnp%ang(ind)%n_symfgrp)))
292 ALLOCATE (workspace%neighbor%ang2(max(1, nnp%ang(ind)%n_symfgrp)))
293 workspace%neighbor%n_rad(:) = 0
294 workspace%neighbor%n_ang1(:) = 0
295 workspace%neighbor%n_ang2(:) = 0
296 workspace%neighbor%pbc_copies = 0
297
298 ! Per-group dG/dr buffers: container arrays sized to n_symfgrp and each
299 ! entry's n_symf recorded. The %data slab stays unallocated until
300 ! nnp_grp_grow_dGdr sees a real neighbour count.
301 CALL nnp_release_dgdr_grp_array(workspace%dGdr_rad)
302 CALL nnp_release_dgdr_grp_array(workspace%dGdr_ang_jj)
303 CALL nnp_release_dgdr_grp_array(workspace%dGdr_ang_kk)
304 ALLOCATE (workspace%dGdr_rad(max(1, nnp%rad(ind)%n_symfgrp)))
305 ALLOCATE (workspace%dGdr_ang_jj(max(1, nnp%ang(ind)%n_symfgrp)))
306 ALLOCATE (workspace%dGdr_ang_kk(max(1, nnp%ang(ind)%n_symfgrp)))
307 DO s = 1, nnp%rad(ind)%n_symfgrp
308 workspace%dGdr_rad(s)%n_symf = nnp%rad(ind)%symfgrp(s)%n_symf
309 workspace%dGdr_rad(s)%cap = 0
310 END DO
311 DO s = 1, nnp%ang(ind)%n_symfgrp
312 workspace%dGdr_ang_jj(s)%n_symf = nnp%ang(ind)%symfgrp(s)%n_symf
313 workspace%dGdr_ang_jj(s)%cap = 0
314 workspace%dGdr_ang_kk(s)%n_symf = nnp%ang(ind)%symfgrp(s)%n_symf
315 workspace%dGdr_ang_kk(s)%cap = 0
316 END DO
317 END associate
318
319 END SUBROUTINE nnp_neighbor_interface_init_workspace_metadata
320
321! **************************************************************************************************
322!> \brief Release the workspace's neighbor%(rad,ang1,ang2) per-group slabs before
323!> re-allocation, keeping the persistent caches that survive a rebuild.
324!> \param workspace per-element scratch workspace whose neighbor%(rad,ang1,ang2) slabs will be released
325! **************************************************************************************************
326 SUBROUTINE nnp_release_neighbor_local(workspace)
327
328 TYPE(nnp_neighbor_workspace_type), INTENT(INOUT) :: workspace
329
330 INTEGER :: s
331
332 IF (ALLOCATED(workspace%neighbor%rad)) THEN
333 DO s = 1, SIZE(workspace%neighbor%rad)
334 IF (ALLOCATED(workspace%neighbor%rad(s)%ind)) DEALLOCATE (workspace%neighbor%rad(s)%ind)
335 IF (ALLOCATED(workspace%neighbor%rad(s)%dist)) DEALLOCATE (workspace%neighbor%rad(s)%dist)
336 END DO
337 DEALLOCATE (workspace%neighbor%rad)
338 END IF
339 IF (ALLOCATED(workspace%neighbor%ang1)) THEN
340 DO s = 1, SIZE(workspace%neighbor%ang1)
341 IF (ALLOCATED(workspace%neighbor%ang1(s)%ind)) DEALLOCATE (workspace%neighbor%ang1(s)%ind)
342 IF (ALLOCATED(workspace%neighbor%ang1(s)%dist)) DEALLOCATE (workspace%neighbor%ang1(s)%dist)
343 END DO
344 DEALLOCATE (workspace%neighbor%ang1)
345 END IF
346 IF (ALLOCATED(workspace%neighbor%ang2)) THEN
347 DO s = 1, SIZE(workspace%neighbor%ang2)
348 IF (ALLOCATED(workspace%neighbor%ang2(s)%ind)) DEALLOCATE (workspace%neighbor%ang2(s)%ind)
349 IF (ALLOCATED(workspace%neighbor%ang2(s)%dist)) DEALLOCATE (workspace%neighbor%ang2(s)%dist)
350 END DO
351 DEALLOCATE (workspace%neighbor%ang2)
352 END IF
353 IF (ALLOCATED(workspace%neighbor%n_rad)) DEALLOCATE (workspace%neighbor%n_rad)
354 IF (ALLOCATED(workspace%neighbor%n_ang1)) DEALLOCATE (workspace%neighbor%n_ang1)
355 IF (ALLOCATED(workspace%neighbor%n_ang2)) DEALLOCATE (workspace%neighbor%n_ang2)
356 workspace%neighbor%pbc_copies = -1
357
358 END SUBROUTINE nnp_release_neighbor_local
359
360! **************************************************************************************************
361!> \brief Release every per-group dG/dr buffer in a container array, then deallocate the container.
362!> \param grps per-group dG/dr container array to release (each entry's %data is freed first)
363! **************************************************************************************************
364 SUBROUTINE nnp_release_dgdr_grp_array(grps)
365
366 TYPE(nnp_dgdr_grp_type), ALLOCATABLE, &
367 INTENT(INOUT) :: grps(:)
368
369 INTEGER :: s
370
371 IF (.NOT. ALLOCATED(grps)) RETURN
372 DO s = 1, SIZE(grps)
373 IF (ALLOCATED(grps(s)%data)) DEALLOCATE (grps(s)%data)
374 grps(s)%cap = 0
375 grps(s)%n_symf = 0
376 END DO
377 DEALLOCATE (grps)
378
379 END SUBROUTINE nnp_release_dgdr_grp_array
380
381! **************************************************************************************************
382!> \brief Ensure a per-group dG/dr buffer holds n_needed neighbours, growing by
383!> 1.5x (with an additive floor) so reallocation amortizes to O(1) over a
384!> trajectory. grp%data is allocated on return (cap >= 1), so callers can
385!> ASSOCIATE-bind it even for a zero-trip loop.
386!> \param grp per-element dGdr group whose %data slab is reallocated if undersized
387!> \param n_needed minimum required capacity (third dim of grp%data)
388!> \author Dhruv Sharma (ds2173@cam.ac.uk)
389! **************************************************************************************************
390 SUBROUTINE nnp_grp_grow_dgdr(grp, n_needed)
391
392 TYPE(nnp_dgdr_grp_type), INTENT(INOUT) :: grp
393 INTEGER, INTENT(IN) :: n_needed
394
395 INTEGER :: new_cap
396
397 IF (ALLOCATED(grp%data) .AND. grp%cap >= n_needed) RETURN
398 IF (ALLOCATED(grp%data)) DEALLOCATE (grp%data)
399 new_cap = max(max(1, n_needed), int(grp%cap*1.5_dp) + 8)
400 ALLOCATE (grp%data(3, max(1, grp%n_symf), new_cap))
401 grp%cap = new_cap
402
403 END SUBROUTINE nnp_grp_grow_dgdr
404
405! **************************************************************************************************
406!> \brief Ensure a per-group (ind, dist) neighbour buffer holds n_needed entries.
407!> Called from inside the linked-cell push loop, so existing entries are
408!> preserved on grow via MOVE_ALLOC. 1.5x growth amortizes reallocation to
409!> O(1) over a trajectory.
410!> \param grp per-species-pair neighbour group whose (ind, dist) buffers grow
411!> \param n_needed minimum required entry count
412!> \author Dhruv Sharma (ds2173@cam.ac.uk)
413! **************************************************************************************************
414 SUBROUTINE nnp_neigh_grp_grow(grp, n_needed)
415
416 TYPE(nnp_neigh_grp_type), INTENT(INOUT) :: grp
417 INTEGER, INTENT(IN) :: n_needed
418
419 INTEGER :: n_old, new_cap
420 INTEGER, ALLOCATABLE :: new_ind(:)
421 REAL(kind=dp), ALLOCATABLE :: new_dist(:, :)
422
423 IF (ALLOCATED(grp%dist) .AND. grp%cap >= n_needed) RETURN
424
425 new_cap = max(max(8, n_needed), int(grp%cap*1.5_dp) + 8)
426
427 IF (ALLOCATED(grp%dist)) THEN
428 n_old = grp%cap
429 ALLOCATE (new_dist(4, new_cap))
430 ALLOCATE (new_ind(new_cap))
431 IF (n_old > 0) THEN
432 new_dist(:, 1:n_old) = grp%dist(:, 1:n_old)
433 new_ind(1:n_old) = grp%ind(1:n_old)
434 END IF
435 CALL move_alloc(new_dist, grp%dist)
436 CALL move_alloc(new_ind, grp%ind)
437 ELSE
438 ALLOCATE (grp%dist(4, new_cap))
439 ALLOCATE (grp%ind(new_cap))
440 END IF
441 grp%cap = new_cap
442
443 END SUBROUTINE nnp_neigh_grp_grow
444
445! **************************************************************************************************
446!> \brief Ensure the four per-element angular cutoff caches hold at least n_needed
447!> entries. These 1D scratch arrays are reused across angular groups within
448!> one nnp_calc_acsf call, so the peak is MAX_s(n_ang1) and MAX_s(n_ang2).
449!> 1.5x lazy growth.
450!> \param workspace per-element workspace whose fc_cache1/dfc_cache1/fc_cache2/dfc_cache2 grow
451!> \param n_needed minimum required cache length
452!> \author Dhruv Sharma (ds2173@cam.ac.uk)
453! **************************************************************************************************
454 SUBROUTINE nnp_workspace_grow_caches(workspace, n_needed)
455
456 TYPE(nnp_neighbor_workspace_type), INTENT(INOUT) :: workspace
457 INTEGER, INTENT(IN) :: n_needed
458
459 INTEGER :: new_cap
460
461 IF (workspace%cache_cap >= n_needed) RETURN
462
463 new_cap = max(max(8, n_needed), int(workspace%cache_cap*1.5_dp) + 8)
464 ! Contents not preserved: nnp_fill_fc_dfc_cache overwrites fully before any read.
465 IF (ALLOCATED(workspace%fc_cache1)) DEALLOCATE (workspace%fc_cache1)
466 IF (ALLOCATED(workspace%dfc_cache1)) DEALLOCATE (workspace%dfc_cache1)
467 IF (ALLOCATED(workspace%fc_cache2)) DEALLOCATE (workspace%fc_cache2)
468 IF (ALLOCATED(workspace%dfc_cache2)) DEALLOCATE (workspace%dfc_cache2)
469 ALLOCATE (workspace%fc_cache1(new_cap))
470 ALLOCATE (workspace%dfc_cache1(new_cap))
471 ALLOCATE (workspace%fc_cache2(new_cap))
472 ALLOCATE (workspace%dfc_cache2(new_cap))
473 workspace%cache_cap = new_cap
474
475 END SUBROUTINE nnp_workspace_grow_caches
476
477END MODULE nnp_neighbor_interface
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Data types for neural network potentials.
subroutine, public nnp_neighbor_interface_state_release(state)
Free the allocatable parts of a neighbour-interface state. Co-located with the type definition to avo...
Per-nnp persistent neighbour-interface state for the NNP hot path. Separates neighbour bookkeeping fr...
subroutine, public nnp_grp_grow_dgdr(grp, n_needed)
Ensure a per-group dG/dr buffer holds n_needed neighbours, growing by 1.5x (with an additive floor) s...
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...
subroutine, public nnp_workspace_grow_caches(workspace, n_needed)
Ensure the four per-element angular cutoff caches hold at least n_needed entries. These 1D scratch ar...
subroutine, public nnp_neighbor_interface_reset_neighbor(nnp, ind)
Reset per-group neighbour counters for one central element before refilling the reusable buffers....
subroutine, public nnp_neighbor_interface_prepare(nnp)
Ensure pair-routing metadata and reusable workspaces are ready for the current NNP model.
Per-(element, SF-group) dG_k/dr buffer, sized to the group's n_symf (no max_*_symf padding) and the o...
Per-SF-group dense neighbour container. cap is the allocated slab size; the live count is nnp_neighbo...
Reusable per-element scratch / persistent caches for the ACSF descriptor and force assembly....
Main data type collecting all relevant data for neural network potentials.