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