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 Define the neighbor list data types and the corresponding functionality
10 : !> \par History
11 : !> - cleaned (23.07.2003,MK)
12 : !> - full refactoring, list iterators (20.10.2010, JGH)
13 : !> - add get_neighbor_list_set_p, return info for a set of neighborlists
14 : !> (07.2014,JGH)
15 : !> \author Matthias Krack (21.06.2000)
16 : ! **************************************************************************************************
17 : MODULE qs_neighbor_list_types
18 :
19 : USE kinds, ONLY: dp
20 : USE util, ONLY: locate,&
21 : sort
22 : #include "./base/base_uses.f90"
23 :
24 : IMPLICIT NONE
25 :
26 : PRIVATE
27 :
28 : ! *** Global parameters (in this module) ***
29 :
30 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_neighbor_list_types'
31 :
32 : ! *** Definition of the data types for a linked list of neighbors ***
33 :
34 : ! **************************************************************************************************
35 : TYPE neighbor_node_type
36 : PRIVATE
37 : TYPE(neighbor_node_type), POINTER :: next_neighbor_node => NULL()
38 : REAL(dp), DIMENSION(3) :: r = -1.0_dp
39 : INTEGER, DIMENSION(3) :: cell = -1
40 : INTEGER :: neighbor = -1
41 : END TYPE neighbor_node_type
42 :
43 : ! **************************************************************************************************
44 : TYPE neighbor_list_type
45 : PRIVATE
46 : TYPE(neighbor_list_type), POINTER :: next_neighbor_list => NULL()
47 : TYPE(neighbor_node_type), POINTER :: first_neighbor_node => NULL(), &
48 : last_neighbor_node => NULL()
49 : INTEGER :: atom = -1, nnode = -1
50 : END TYPE neighbor_list_type
51 :
52 : ! **************************************************************************************************
53 : TYPE neighbor_list_set_type
54 : PRIVATE
55 : TYPE(neighbor_list_type), POINTER :: first_neighbor_list => NULL(), &
56 : last_neighbor_list => NULL()
57 : INTEGER :: nlist = -1
58 : LOGICAL :: symmetric = .FALSE.
59 : END TYPE neighbor_list_set_type
60 :
61 : ! **************************************************************************************************
62 : TYPE neighbor_list_p_type
63 : TYPE(neighbor_list_type), POINTER :: neighbor_list => NULL()
64 : END TYPE neighbor_list_p_type
65 :
66 : ! **************************************************************************************************
67 : TYPE neighbor_list_set_p_type
68 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set => NULL()
69 : INTEGER :: nl_size = -1
70 : INTEGER :: nl_start = -1
71 : INTEGER :: nl_end = -1
72 : TYPE(neighbor_list_task_type), DIMENSION(:), POINTER :: nlist_task => NULL()
73 : END TYPE neighbor_list_set_p_type
74 :
75 : ! **************************************************************************************************
76 : TYPE list_search_type
77 : PRIVATE
78 : INTEGER :: nlist = -1
79 : INTEGER, DIMENSION(:), POINTER :: atom_list => NULL()
80 : INTEGER, DIMENSION(:), POINTER :: atom_index => NULL()
81 : TYPE(neighbor_list_p_type), &
82 : DIMENSION(:), POINTER :: neighbor_list => NULL()
83 : END TYPE list_search_type
84 :
85 : ! **************************************************************************************************
86 : TYPE neighbor_list_task_type
87 : INTEGER :: iatom = -1, jatom = -1, &
88 : ikind = -1, jkind = -1, nkind = -1, &
89 : ilist = -1, nlist = -1, inode = -1, nnode = -1
90 : REAL(KIND=dp), DIMENSION(3) :: r = -1.0_dp
91 : INTEGER, DIMENSION(3) :: cell = -1
92 : TYPE(neighbor_list_task_type), &
93 : POINTER :: next => NULL() ! Pointer for forming a linked list of tasks
94 : END TYPE neighbor_list_task_type
95 :
96 : INTERFACE nl_sub_iterate
97 : MODULE PROCEDURE nl_sub_iterate
98 : MODULE PROCEDURE nl_sub_iterate_ref
99 : END INTERFACE
100 :
101 : ! **************************************************************************************************
102 : ! Neighbor List Iterator
103 : ! **************************************************************************************************
104 : TYPE neighbor_list_iterator_type
105 : PRIVATE
106 : INTEGER :: ikind = -1, jkind = -1, ilist = -1, inode = -1
107 : INTEGER :: nkind = -1, nlist = -1, nnode = -1
108 : INTEGER :: iatom = -1, jatom = -1
109 : TYPE(neighbor_list_set_p_type), &
110 : DIMENSION(:), POINTER :: nl => NULL()
111 : TYPE(neighbor_list_type), POINTER :: neighbor_list => NULL()
112 : TYPE(neighbor_node_type), POINTER :: neighbor_node => NULL()
113 : TYPE(list_search_type), &
114 : DIMENSION(:), POINTER :: list_search => NULL()
115 : END TYPE neighbor_list_iterator_type
116 :
117 : TYPE neighbor_list_iterator_p_type
118 : PRIVATE
119 : TYPE(neighbor_list_iterator_type), POINTER :: neighbor_list_iterator => NULL()
120 : INTEGER :: last = -1
121 : END TYPE neighbor_list_iterator_p_type
122 : ! **************************************************************************************************
123 :
124 : ! *** Public data types ***
125 :
126 : PUBLIC :: neighbor_list_p_type, &
127 : neighbor_list_set_type, &
128 : neighbor_list_set_p_type, &
129 : neighbor_list_task_type
130 :
131 : ! *** Public subroutines ***
132 :
133 : PUBLIC :: add_neighbor_list, &
134 : add_neighbor_node, &
135 : allocate_neighbor_list_set, &
136 : deallocate_neighbor_list_set, &
137 : release_neighbor_list_sets, &
138 : get_iterator_task, &
139 : get_neighbor_list_set, &
140 : get_neighbor_list_set_p
141 :
142 : ! *** Iterator functions and types ***
143 :
144 : PUBLIC :: neighbor_list_iterator_p_type, &
145 : neighbor_list_iterator_create, &
146 : neighbor_list_iterator_release, &
147 : neighbor_list_iterate, &
148 : nl_set_sub_iterator, &
149 : nl_sub_iterate, &
150 : get_iterator_info
151 :
152 : CONTAINS
153 :
154 : ! **************************************************************************************************
155 : !> \brief Neighbor list iterator functions
156 : !> \param iterator_set ...
157 : !> \param nl ...
158 : !> \param search ...
159 : !> \param nthread ...
160 : !> \date 28.07.2010
161 : !> \author jhu
162 : !> \version 1.0
163 : ! **************************************************************************************************
164 4014580 : SUBROUTINE neighbor_list_iterator_create(iterator_set, nl, search, nthread)
165 : TYPE(neighbor_list_iterator_p_type), &
166 : DIMENSION(:), POINTER :: iterator_set
167 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
168 : POINTER :: nl
169 : LOGICAL, INTENT(IN), OPTIONAL :: search
170 : INTEGER, INTENT(IN), OPTIONAL :: nthread
171 :
172 : INTEGER :: iatom, il, ilist, mthread, nlist
173 4014580 : TYPE(list_search_type), DIMENSION(:), POINTER :: list_search
174 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
175 : TYPE(neighbor_list_type), POINTER :: neighbor_list
176 :
177 4014580 : mthread = 1
178 92355 : IF (PRESENT(nthread)) mthread = nthread
179 :
180 16058320 : ALLOCATE (iterator_set(0:mthread - 1))
181 :
182 8029160 : DO il = 0, mthread - 1
183 4014580 : ALLOCATE (iterator_set(il)%neighbor_list_iterator)
184 :
185 4014580 : iterator => iterator_set(il)%neighbor_list_iterator
186 :
187 4014580 : iterator%nl => nl
188 :
189 4014580 : iterator%ikind = 0
190 4014580 : iterator%jkind = 0
191 4014580 : iterator%nkind = NINT(SQRT(REAL(SIZE(nl), dp)))
192 :
193 4014580 : iterator%ilist = 0
194 4014580 : iterator%nlist = 0
195 4014580 : iterator%inode = 0
196 4014580 : iterator%nnode = 0
197 :
198 4014580 : iterator%iatom = 0
199 4014580 : iterator%jatom = 0
200 :
201 4014580 : NULLIFY (iterator%neighbor_list)
202 4014580 : NULLIFY (iterator%neighbor_node)
203 8029160 : NULLIFY (iterator%list_search)
204 : END DO
205 :
206 8029160 : iterator_set(:)%last = 0
207 :
208 4014580 : IF (PRESENT(search)) THEN
209 46797 : IF (search) THEN
210 256026 : ALLOCATE (list_search(SIZE(nl)))
211 162432 : DO il = 1, SIZE(nl)
212 162432 : IF (ASSOCIATED(nl(il)%neighbor_list_set)) THEN
213 114503 : CALL get_neighbor_list_set(neighbor_list_set=nl(il)%neighbor_list_set, nlist=nlist)
214 114503 : list_search(il)%nlist = nlist
215 314130 : ALLOCATE (list_search(il)%atom_list(nlist))
216 199627 : ALLOCATE (list_search(il)%atom_index(nlist))
217 457171 : ALLOCATE (list_search(il)%neighbor_list(nlist))
218 :
219 114503 : NULLIFY (neighbor_list)
220 257544 : DO ilist = 1, nlist
221 143041 : IF (.NOT. ASSOCIATED(neighbor_list)) THEN
222 85124 : neighbor_list => first_list(nl(il)%neighbor_list_set)
223 : ELSE
224 57917 : neighbor_list => neighbor_list%next_neighbor_list
225 : END IF
226 143041 : CALL get_neighbor_list(neighbor_list=neighbor_list, atom=iatom)
227 143041 : list_search(il)%atom_list(ilist) = iatom
228 257544 : list_search(il)%neighbor_list(ilist)%neighbor_list => neighbor_list
229 : END DO
230 229006 : CALL sort(list_search(il)%atom_list, nlist, list_search(il)%atom_index)
231 :
232 : ELSE
233 1132 : list_search(il)%nlist = -1
234 1132 : NULLIFY (list_search(il)%atom_list, list_search(il)%atom_index, list_search(il)%neighbor_list)
235 : END IF
236 : END DO
237 93594 : DO il = 0, mthread - 1
238 46797 : iterator => iterator_set(il)%neighbor_list_iterator
239 93594 : iterator%list_search => list_search
240 : END DO
241 : END IF
242 : END IF
243 :
244 4014580 : END SUBROUTINE neighbor_list_iterator_create
245 :
246 : ! **************************************************************************************************
247 : !> \brief ...
248 : !> \param iterator_set ...
249 : ! **************************************************************************************************
250 4014580 : SUBROUTINE neighbor_list_iterator_release(iterator_set)
251 : TYPE(neighbor_list_iterator_p_type), &
252 : DIMENSION(:), POINTER :: iterator_set
253 :
254 : INTEGER :: il, mthread
255 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
256 :
257 : !all threads have the same search list
258 :
259 4014580 : iterator => iterator_set(0)%neighbor_list_iterator
260 4014580 : IF (ASSOCIATED(iterator%list_search)) THEN
261 162432 : DO il = 1, SIZE(iterator%list_search)
262 162432 : IF (iterator%list_search(il)%nlist >= 0) THEN
263 114503 : DEALLOCATE (iterator%list_search(il)%atom_list)
264 114503 : DEALLOCATE (iterator%list_search(il)%atom_index)
265 114503 : DEALLOCATE (iterator%list_search(il)%neighbor_list)
266 : END IF
267 : END DO
268 46797 : DEALLOCATE (iterator%list_search)
269 : END IF
270 :
271 4014580 : mthread = SIZE(iterator_set)
272 8029160 : DO il = 0, mthread - 1
273 8029160 : DEALLOCATE (iterator_set(il)%neighbor_list_iterator)
274 : END DO
275 4014580 : DEALLOCATE (iterator_set)
276 :
277 4014580 : END SUBROUTINE neighbor_list_iterator_release
278 :
279 : ! **************************************************************************************************
280 : !> \brief ...
281 : !> \param iterator_set ...
282 : !> \param ikind ...
283 : !> \param jkind ...
284 : !> \param iatom ...
285 : !> \param mepos ...
286 : ! **************************************************************************************************
287 3888878 : SUBROUTINE nl_set_sub_iterator(iterator_set, ikind, jkind, iatom, mepos)
288 : TYPE(neighbor_list_iterator_p_type), &
289 : DIMENSION(:), POINTER :: iterator_set
290 : INTEGER, INTENT(IN) :: ikind, jkind, iatom
291 : INTEGER, INTENT(IN), OPTIONAL :: mepos
292 :
293 : INTEGER :: i, ij, ilist, me, nlist, nnode
294 : TYPE(list_search_type), POINTER :: list_search
295 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
296 : TYPE(neighbor_list_type), POINTER :: neighbor_list
297 :
298 3888878 : IF (PRESENT(mepos)) THEN
299 3316218 : me = mepos
300 : ELSE
301 : me = 0
302 : END IF
303 :
304 : ! Set up my thread-local iterator for the list of iatom / jkind nodes
305 :
306 3888878 : iterator => iterator_set(me)%neighbor_list_iterator
307 3888878 : ij = ikind + iterator%nkind*(jkind - 1)
308 3888878 : IF (ASSOCIATED(iterator%list_search)) THEN
309 3888878 : list_search => iterator%list_search(ij)
310 3888878 : nlist = list_search%nlist
311 3888878 : ilist = 0
312 3888878 : NULLIFY (neighbor_list)
313 3888878 : IF (nlist > 0) THEN
314 3878246 : i = locate(list_search%atom_list, iatom)
315 3878246 : i = list_search%atom_index(i)
316 3878246 : IF (i > 0) neighbor_list => list_search%neighbor_list(i)%neighbor_list
317 : ilist = i
318 : END IF
319 3888878 : IF (ASSOCIATED(neighbor_list)) THEN
320 3878246 : CALL get_neighbor_list(neighbor_list=neighbor_list, nnode=nnode)
321 : ELSE
322 10632 : nnode = 0
323 : END IF
324 : ELSE
325 0 : CPABORT("iterator%list_search is not available")
326 : END IF
327 :
328 3888878 : iterator%ikind = ikind
329 3888878 : iterator%jkind = jkind
330 :
331 3888878 : iterator%ilist = ilist
332 3888878 : iterator%nlist = nlist
333 3888878 : iterator%inode = 0
334 3888878 : iterator%nnode = nnode
335 :
336 3888878 : iterator%iatom = iatom
337 3888878 : iterator%jatom = 0
338 :
339 3888878 : iterator%neighbor_list => neighbor_list
340 3888878 : NULLIFY (iterator%neighbor_node)
341 :
342 3888878 : END SUBROUTINE nl_set_sub_iterator
343 :
344 : ! **************************************************************************************************
345 : !> \brief ...
346 : !> \param iterator_set ...
347 : !> \param mepos ...
348 : !> \return ...
349 : ! **************************************************************************************************
350 2454332350 : FUNCTION neighbor_list_iterate(iterator_set, mepos) RESULT(istat)
351 : TYPE(neighbor_list_iterator_p_type), &
352 : DIMENSION(:), POINTER :: iterator_set
353 : INTEGER, INTENT(IN), OPTIONAL :: mepos
354 : INTEGER :: istat
355 :
356 : INTEGER :: iab, last, me
357 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
358 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
359 2454332350 : POINTER :: nl
360 :
361 0 : IF (SIZE(iterator_set) /= 1 .AND. .NOT. PRESENT(mepos)) THEN
362 0 : CPABORT("Parallel iterator calls must include 'mepos'")
363 : END IF
364 :
365 2454332350 : IF (PRESENT(mepos)) THEN
366 11591924 : me = mepos
367 : ELSE
368 : me = 0
369 : END IF
370 :
371 2454332350 : istat = 0
372 :
373 4908664700 : !$OMP CRITICAL(neighbour_list_iterate_critical)
374 2454332350 : last = iterator_set(0)%last
375 2454332350 : IF (last /= me) THEN
376 0 : iterator_set(me)%neighbor_list_iterator = iterator_set(last)%neighbor_list_iterator
377 : END IF
378 2454332350 : iterator => iterator_set(me)%neighbor_list_iterator
379 2454332350 : nl => iterator%nl
380 :
381 2454332350 : IF (iterator%inode < iterator%nnode) THEN
382 : ! we can be sure that there is another node in this list
383 2433185605 : iterator%inode = iterator%inode + 1
384 2433185605 : iterator%neighbor_node => iterator%neighbor_node%next_neighbor_node
385 : ELSE
386 21146745 : iab = MAX(iterator%ikind + iterator%nkind*(iterator%jkind - 1), 0)
387 12188436 : kindloop: DO ! look for the next list with nnode /= 0
388 : listloop: DO
389 34681217 : IF (iterator%ilist >= iterator%nlist) EXIT listloop
390 18524998 : iterator%ilist = iterator%ilist + 1
391 18524998 : IF (ASSOCIATED(iterator%neighbor_list)) THEN
392 9658468 : iterator%neighbor_list => iterator%neighbor_list%next_neighbor_list
393 : ELSE
394 8866530 : iterator%neighbor_list => first_list(nl(iab)%neighbor_list_set)
395 : END IF
396 : CALL get_neighbor_list(neighbor_list=iterator%neighbor_list, atom=iterator%iatom, &
397 18524998 : nnode=iterator%nnode)
398 34681217 : IF (iterator%nnode > 0) EXIT kindloop
399 : END DO listloop
400 33335181 : IF (iab >= iterator%nkind**2) THEN
401 : istat = 1
402 : EXIT kindloop
403 : ELSE
404 12188436 : iab = iab + 1
405 12188436 : iterator%jkind = (iab - 1)/iterator%nkind + 1
406 12188436 : iterator%ikind = iab - iterator%nkind*(iterator%jkind - 1)
407 12188436 : iterator%ilist = 0
408 12188436 : IF (.NOT. ASSOCIATED(nl(iab)%neighbor_list_set)) THEN
409 : iterator%ilist = 0
410 149164 : iterator%nlist = 0
411 : ELSE
412 : CALL get_neighbor_list_set(neighbor_list_set= &
413 12039272 : nl(iab)%neighbor_list_set, nlist=iterator%nlist)
414 12039272 : iterator%ilist = 0
415 : END IF
416 12188436 : NULLIFY (iterator%neighbor_list)
417 : END IF
418 : END DO kindloop
419 21146745 : IF (istat == 0) THEN
420 17178962 : iterator%inode = 1
421 17178962 : iterator%neighbor_node => first_node(iterator%neighbor_list)
422 : END IF
423 : END IF
424 : IF (istat == 0) THEN
425 2450364567 : CALL get_neighbor_node(neighbor_node=iterator%neighbor_node, neighbor=iterator%jatom)
426 : END IF
427 :
428 : ! mark the last iterator updated
429 4908664700 : iterator_set(:)%last = me
430 : !$OMP END CRITICAL(neighbour_list_iterate_critical)
431 :
432 2454332350 : END FUNCTION neighbor_list_iterate
433 :
434 : ! **************************************************************************************************
435 : !> \brief ...
436 : !> \param iterator_set ...
437 : !> \param mepos ...
438 : !> \return ...
439 : ! **************************************************************************************************
440 238602049 : FUNCTION nl_sub_iterate(iterator_set, mepos) RESULT(istat)
441 : TYPE(neighbor_list_iterator_p_type), &
442 : DIMENSION(:), POINTER :: iterator_set
443 : INTEGER, INTENT(IN), OPTIONAL :: mepos
444 : INTEGER :: istat
445 :
446 : INTEGER :: me
447 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
448 :
449 : ! Each thread's sub-iterator are independent, no need to synchronise with other threads
450 :
451 238602049 : IF (PRESENT(mepos)) THEN
452 232453069 : me = mepos
453 : ELSE
454 : me = 0
455 : END IF
456 :
457 238602049 : istat = 0
458 :
459 238602049 : iterator => iterator_set(me)%neighbor_list_iterator
460 :
461 238602049 : IF (ASSOCIATED(iterator%neighbor_list)) THEN
462 238591417 : IF (iterator%inode >= iterator%nnode) THEN
463 : ! end of loop
464 : istat = 1
465 234931768 : ELSE IF (iterator%inode == 0) THEN
466 3579624 : iterator%inode = 1
467 3579624 : iterator%neighbor_node => first_node(iterator%neighbor_list)
468 231352144 : ELSE IF (iterator%inode > 0) THEN
469 : ! we can be sure that there is another node in this list
470 231352144 : iterator%inode = iterator%inode + 1
471 231352144 : iterator%neighbor_node => iterator%neighbor_node%next_neighbor_node
472 : ELSE
473 0 : CPABORT("wrong")
474 : END IF
475 : ELSE
476 : ! no list available
477 : istat = 1
478 : END IF
479 : IF (istat == 0) THEN
480 234931768 : CALL get_neighbor_node(neighbor_node=iterator%neighbor_node, neighbor=iterator%jatom)
481 : END IF
482 :
483 238602049 : END FUNCTION nl_sub_iterate
484 :
485 : ! **************************************************************************************************
486 : !> \brief wrap nl_sub_iterate s.t. external loop over kinds and calls to nl_set_sub_iterator
487 : !> are no longer needed. This fixes first atom of iter_sub to second atom of iter_ref.
488 : !> \param iter_sub ...
489 : !> \param iter_ref ...
490 : !> \param mepos ...
491 : !> \return ...
492 : ! **************************************************************************************************
493 5922917 : RECURSIVE FUNCTION nl_sub_iterate_ref(iter_sub, iter_ref, mepos) RESULT(iter_stat)
494 : TYPE(neighbor_list_iterator_p_type), &
495 : DIMENSION(:), POINTER :: iter_sub, iter_ref
496 : INTEGER, INTENT(IN), OPTIONAL :: mepos
497 : INTEGER :: iter_stat
498 :
499 : INTEGER :: atom_ref, kind_ref, kind_sub, me, nkind
500 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
501 :
502 5922917 : IF (PRESENT(mepos)) THEN
503 0 : me = mepos
504 : ELSE
505 : me = 0
506 : END IF
507 :
508 5922917 : iterator => iter_sub(me)%neighbor_list_iterator
509 5922917 : kind_sub = iterator%jkind
510 :
511 5922917 : CALL get_iterator_info(iter_ref, jatom=atom_ref, jkind=kind_ref)
512 :
513 5922917 : IF (iterator%inode == 0) THEN
514 218597 : CALL nl_set_sub_iterator(iter_sub, kind_ref, MAX(kind_sub, 1), atom_ref)
515 : END IF
516 5922917 : iter_stat = nl_sub_iterate(iter_sub)
517 5922917 : IF (iter_stat == 0) RETURN
518 :
519 218597 : nkind = iterator%nkind
520 :
521 218597 : IF (kind_sub == nkind) THEN
522 139549 : CALL nl_set_sub_iterator(iter_sub, kind_ref, 1, atom_ref)
523 139549 : RETURN
524 : ELSE
525 79048 : kind_sub = kind_sub + 1
526 79048 : CALL nl_set_sub_iterator(iter_sub, kind_ref, kind_sub, atom_ref)
527 79048 : iter_stat = nl_sub_iterate_ref(iter_sub, iter_ref)
528 : END IF
529 :
530 79048 : END FUNCTION nl_sub_iterate_ref
531 :
532 : ! **************************************************************************************************
533 : !> \brief ...
534 : !> \param iterator_set ...
535 : !> \param mepos ...
536 : !> \param ikind ...
537 : !> \param jkind ...
538 : !> \param nkind ...
539 : !> \param ilist ...
540 : !> \param nlist ...
541 : !> \param inode ...
542 : !> \param nnode ...
543 : !> \param iatom ...
544 : !> \param jatom ...
545 : !> \param r ...
546 : !> \param cell ...
547 : ! **************************************************************************************************
548 2762733806 : SUBROUTINE get_iterator_info(iterator_set, mepos, &
549 : ikind, jkind, nkind, ilist, nlist, inode, nnode, iatom, jatom, r, cell)
550 : TYPE(neighbor_list_iterator_p_type), &
551 : DIMENSION(:), POINTER :: iterator_set
552 : INTEGER, INTENT(IN), OPTIONAL :: mepos
553 : INTEGER, OPTIONAL :: ikind, jkind, nkind, ilist, nlist, &
554 : inode, nnode, iatom, jatom
555 : REAL(dp), DIMENSION(3), OPTIONAL :: r
556 : INTEGER, DIMENSION(3), OPTIONAL :: cell
557 :
558 : INTEGER :: me
559 : TYPE(neighbor_list_iterator_type), POINTER :: iterator
560 :
561 2762733806 : CPASSERT(ASSOCIATED(iterator_set))
562 2762733806 : IF ((SIZE(iterator_set) /= 1) .AND. (.NOT. PRESENT(mepos))) THEN
563 0 : CPABORT("Parallel iterator calls must include 'mepos'")
564 : END IF
565 2762733806 : IF (PRESENT(mepos)) THEN
566 240658423 : me = mepos
567 : ELSE
568 : me = 0
569 : END IF
570 2762733806 : iterator => iterator_set(me)%neighbor_list_iterator
571 :
572 2762733806 : IF (PRESENT(ikind)) ikind = iterator%ikind
573 2762733806 : IF (PRESENT(jkind)) jkind = iterator%jkind
574 2762733806 : IF (PRESENT(nkind)) nkind = iterator%nkind
575 2762733806 : IF (PRESENT(ilist)) ilist = iterator%ilist
576 2762733806 : IF (PRESENT(nlist)) nlist = iterator%nlist
577 2762733806 : IF (PRESENT(inode)) inode = iterator%inode
578 2762733806 : IF (PRESENT(nnode)) nnode = iterator%nnode
579 2762733806 : IF (PRESENT(iatom)) iatom = iterator%iatom
580 2762733806 : IF (PRESENT(jatom)) jatom = iterator%jatom
581 2762733806 : IF (PRESENT(r)) THEN
582 511506739 : CALL get_neighbor_node(neighbor_node=iterator%neighbor_node, r=r)
583 : END IF
584 2762733806 : IF (PRESENT(cell)) THEN
585 217714063 : CALL get_neighbor_node(neighbor_node=iterator%neighbor_node, cell=cell)
586 : END IF
587 :
588 2762733806 : END SUBROUTINE get_iterator_info
589 :
590 : ! **************************************************************************************************
591 : !> \brief Captures the current state of the iterator in a neighbor_list_task_type
592 : !> \param iterator_set the iterator / array of iterators (for multiple threads)
593 : !> \param task the task structure which is returned
594 : !> \param mepos OpenMP thread index
595 : ! **************************************************************************************************
596 476630312 : SUBROUTINE get_iterator_task(iterator_set, task, mepos)
597 : TYPE(neighbor_list_iterator_p_type), &
598 : DIMENSION(:), POINTER :: iterator_set
599 : TYPE(neighbor_list_task_type), INTENT(OUT) :: task
600 : INTEGER, INTENT(IN), OPTIONAL :: mepos
601 :
602 59578789 : IF (PRESENT(mepos)) THEN
603 : CALL get_iterator_info(iterator_set, mepos=mepos, ikind=task%ikind, jkind=task%jkind, &
604 : nkind=task%nkind, &
605 : ilist=task%ilist, nlist=task%nlist, &
606 : inode=task%inode, nnode=task%nnode, &
607 : iatom=task%iatom, jatom=task%jatom, &
608 0 : r=task%r, cell=task%cell)
609 : ELSE
610 : CALL get_iterator_info(iterator_set, ikind=task%ikind, jkind=task%jkind, &
611 : nkind=task%nkind, &
612 : ilist=task%ilist, nlist=task%nlist, &
613 : inode=task%inode, nnode=task%nnode, &
614 : iatom=task%iatom, jatom=task%jatom, &
615 59578789 : r=task%r, cell=task%cell)
616 : END IF
617 :
618 59578789 : NULLIFY (task%next)
619 :
620 59578789 : END SUBROUTINE get_iterator_task
621 :
622 : ! **************************************************************************************************
623 : !> \brief Add a new neighbor list to a neighbor list set.
624 : !> \param neighbor_list_set ...
625 : !> \param atom ...
626 : !> \param neighbor_list ...
627 : !> \date 13.09.2000
628 : !> \author MK
629 : !> \version 1.0
630 : ! **************************************************************************************************
631 844001 : SUBROUTINE add_neighbor_list(neighbor_list_set, atom, neighbor_list)
632 :
633 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
634 : INTEGER, INTENT(IN) :: atom
635 : TYPE(neighbor_list_type), POINTER :: neighbor_list
636 :
637 : TYPE(neighbor_list_type), POINTER :: new_neighbor_list
638 :
639 844001 : IF (ASSOCIATED(neighbor_list_set)) THEN
640 :
641 844001 : IF (ASSOCIATED(neighbor_list_set%last_neighbor_list)) THEN
642 :
643 : new_neighbor_list => &
644 417086 : neighbor_list_set%last_neighbor_list%next_neighbor_list
645 :
646 417086 : IF (.NOT. ASSOCIATED(new_neighbor_list)) THEN
647 :
648 : ! *** Allocate a new neighbor list ***
649 :
650 417086 : ALLOCATE (new_neighbor_list)
651 :
652 : NULLIFY (new_neighbor_list%next_neighbor_list)
653 : NULLIFY (new_neighbor_list%first_neighbor_node)
654 :
655 : ! *** Link the new neighbor list to the neighbor list set ***
656 :
657 417086 : neighbor_list_set%last_neighbor_list%next_neighbor_list => new_neighbor_list
658 :
659 : END IF
660 :
661 : ELSE
662 :
663 426915 : new_neighbor_list => neighbor_list_set%first_neighbor_list
664 :
665 426915 : IF (.NOT. ASSOCIATED(new_neighbor_list)) THEN
666 :
667 : ! *** Allocate a new first neighbor list ***
668 :
669 426915 : ALLOCATE (new_neighbor_list)
670 :
671 : NULLIFY (new_neighbor_list%next_neighbor_list)
672 : NULLIFY (new_neighbor_list%first_neighbor_node)
673 :
674 : ! *** Link the new first neighbor list to the neighbor list set ***
675 :
676 426915 : neighbor_list_set%first_neighbor_list => new_neighbor_list
677 :
678 : END IF
679 :
680 : END IF
681 :
682 : ! *** Store the data set of the new neighbor list ***
683 :
684 844001 : NULLIFY (new_neighbor_list%last_neighbor_node)
685 844001 : new_neighbor_list%atom = atom
686 844001 : new_neighbor_list%nnode = 0
687 :
688 : ! *** Update the pointer to the last neighbor ***
689 : ! *** list of the neighbor list set ***
690 :
691 844001 : neighbor_list_set%last_neighbor_list => new_neighbor_list
692 :
693 : ! *** Increment the neighbor list counter ***
694 :
695 844001 : neighbor_list_set%nlist = neighbor_list_set%nlist + 1
696 :
697 : ! *** Return a pointer to the new neighbor list ***
698 :
699 844001 : neighbor_list => new_neighbor_list
700 :
701 : ELSE
702 :
703 0 : CPABORT("The requested neighbor list set is not associated")
704 :
705 : END IF
706 :
707 844001 : END SUBROUTINE add_neighbor_list
708 :
709 : ! **************************************************************************************************
710 : !> \brief Add a new neighbor list node to a neighbor list.
711 : !> \param neighbor_list ...
712 : !> \param neighbor ...
713 : !> \param cell ...
714 : !> \param r ...
715 : !> \param exclusion_list ...
716 : !> \param nkind ...
717 : !> \date 23.06.2000
718 : !> \author MK
719 : !> \version 1.0
720 : ! **************************************************************************************************
721 58525890 : SUBROUTINE add_neighbor_node(neighbor_list, neighbor, cell, r, exclusion_list, nkind)
722 :
723 : TYPE(neighbor_list_type), POINTER :: neighbor_list
724 : INTEGER, INTENT(IN) :: neighbor
725 : INTEGER, DIMENSION(3), INTENT(IN) :: cell
726 : REAL(dp), DIMENSION(3), INTENT(IN) :: r
727 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: exclusion_list
728 : INTEGER, INTENT(IN), OPTIONAL :: nkind
729 :
730 : INTEGER :: iatom, my_nkind
731 : TYPE(neighbor_node_type), POINTER :: new_neighbor_node
732 :
733 58525890 : IF (ASSOCIATED(neighbor_list)) THEN
734 :
735 : ! *** Check for exclusions ***
736 :
737 58525890 : IF (PRESENT(exclusion_list)) THEN
738 0 : IF (ASSOCIATED(exclusion_list)) THEN
739 0 : DO iatom = 1, SIZE(exclusion_list)
740 0 : IF (exclusion_list(iatom) == 0) EXIT
741 0 : IF (exclusion_list(iatom) == neighbor) RETURN
742 : END DO
743 : END IF
744 : END IF
745 :
746 58525890 : my_nkind = 0
747 58525890 : IF (PRESENT(nkind)) my_nkind = nkind
748 :
749 58525890 : IF (ASSOCIATED(neighbor_list%last_neighbor_node)) THEN
750 :
751 57757660 : new_neighbor_node => neighbor_list%last_neighbor_node%next_neighbor_node
752 :
753 57757660 : IF (.NOT. ASSOCIATED(new_neighbor_node)) THEN
754 :
755 : ! *** Allocate a new neighbor node ***
756 :
757 404303620 : ALLOCATE (new_neighbor_node)
758 :
759 : NULLIFY (new_neighbor_node%next_neighbor_node)
760 :
761 : ! *** Link the new neighbor node to the neighbor list ***
762 :
763 57757660 : neighbor_list%last_neighbor_node%next_neighbor_node => new_neighbor_node
764 :
765 : END IF
766 :
767 : ELSE
768 :
769 768230 : new_neighbor_node => neighbor_list%first_neighbor_node
770 :
771 768230 : IF (.NOT. ASSOCIATED(new_neighbor_node)) THEN
772 :
773 : ! *** Allocate a new first neighbor node ***
774 :
775 5377610 : ALLOCATE (new_neighbor_node)
776 :
777 : NULLIFY (new_neighbor_node%next_neighbor_node)
778 :
779 : ! *** Link the new first neighbor node to the neighbor list ***
780 :
781 768230 : neighbor_list%first_neighbor_node => new_neighbor_node
782 :
783 : END IF
784 :
785 : END IF
786 :
787 : ! *** Store the data set of the new neighbor ***
788 :
789 58525890 : new_neighbor_node%neighbor = neighbor
790 234103560 : new_neighbor_node%cell(:) = cell(:)
791 234103560 : new_neighbor_node%r(:) = r(:)
792 :
793 : ! *** Update the pointer to the last neighbor node of the neighbor list ***
794 :
795 58525890 : neighbor_list%last_neighbor_node => new_neighbor_node
796 :
797 : ! *** Increment the neighbor node counter ***
798 :
799 58525890 : neighbor_list%nnode = neighbor_list%nnode + 1
800 :
801 : ELSE
802 :
803 0 : CPABORT("The requested neighbor list is not associated")
804 :
805 : END IF
806 :
807 : END SUBROUTINE add_neighbor_node
808 :
809 : ! **************************************************************************************************
810 : !> \brief Allocate and initialize a set of neighbor lists.
811 : !> \param neighbor_list_set ...
812 : !> \param symmetric ...
813 : !> \date 23.06.2000
814 : !> \author MK
815 : !> \version 1.0
816 : ! **************************************************************************************************
817 605635 : SUBROUTINE allocate_neighbor_list_set(neighbor_list_set, symmetric)
818 :
819 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
820 : LOGICAL, INTENT(IN) :: symmetric
821 :
822 : ! *** Deallocate the old neighbor list set ***
823 :
824 605635 : IF (ASSOCIATED(neighbor_list_set)) THEN
825 0 : CALL deallocate_neighbor_list_set(neighbor_list_set)
826 : END IF
827 :
828 : ! *** Allocate a set of neighbor lists ***
829 :
830 605635 : ALLOCATE (neighbor_list_set)
831 :
832 : NULLIFY (neighbor_list_set%first_neighbor_list)
833 :
834 : ! *** Initialize the pointers to the first neighbor list ***
835 :
836 605635 : CALL init_neighbor_list_set(neighbor_list_set, symmetric)
837 :
838 605635 : END SUBROUTINE allocate_neighbor_list_set
839 :
840 : ! **************************************************************************************************
841 : !> \brief Deallocate a neighbor list.
842 : !> \param neighbor_list ...
843 : !> \date 20.09.2002
844 : !> \author MK
845 : !> \version 1.0
846 : ! **************************************************************************************************
847 844001 : SUBROUTINE deallocate_neighbor_list(neighbor_list)
848 :
849 : TYPE(neighbor_list_type), POINTER :: neighbor_list
850 :
851 : TYPE(neighbor_node_type), POINTER :: neighbor_node, next_neighbor_node
852 :
853 844001 : IF (ASSOCIATED(neighbor_list)) THEN
854 :
855 844001 : neighbor_node => neighbor_list%first_neighbor_node
856 :
857 59369891 : DO WHILE (ASSOCIATED(neighbor_node))
858 58525890 : next_neighbor_node => neighbor_node%next_neighbor_node
859 58525890 : DEALLOCATE (neighbor_node)
860 58525890 : neighbor_node => next_neighbor_node
861 : END DO
862 :
863 844001 : DEALLOCATE (neighbor_list)
864 :
865 : END IF
866 :
867 844001 : END SUBROUTINE deallocate_neighbor_list
868 :
869 : ! **************************************************************************************************
870 : !> \brief Deallocate a neighbor list set.
871 : !> \param neighbor_list_set ...
872 : !> \date 03.11.2000
873 : !> \author MK
874 : !> \version 1.0
875 : ! **************************************************************************************************
876 665529 : SUBROUTINE deallocate_neighbor_list_set(neighbor_list_set)
877 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
878 :
879 : TYPE(neighbor_list_type), POINTER :: neighbor_list, next_neighbor_list
880 :
881 665529 : IF (ASSOCIATED(neighbor_list_set)) THEN
882 :
883 605635 : neighbor_list => neighbor_list_set%first_neighbor_list
884 :
885 1449636 : DO WHILE (ASSOCIATED(neighbor_list))
886 844001 : next_neighbor_list => neighbor_list%next_neighbor_list
887 844001 : CALL deallocate_neighbor_list(neighbor_list)
888 844001 : neighbor_list => next_neighbor_list
889 : END DO
890 :
891 605635 : DEALLOCATE (neighbor_list_set)
892 :
893 : END IF
894 :
895 665529 : END SUBROUTINE deallocate_neighbor_list_set
896 :
897 : ! **************************************************************************************************
898 : !> \brief Return a pointer to the first neighbor list of a neighbor list set.
899 : !> \param neighbor_list_set ...
900 : !> \return ...
901 : !> \date 13.09.2000
902 : !> \author MK
903 : !> \version 1.0
904 : ! **************************************************************************************************
905 8951654 : FUNCTION first_list(neighbor_list_set) RESULT(first_neighbor_list)
906 :
907 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
908 : TYPE(neighbor_list_type), POINTER :: first_neighbor_list
909 :
910 8951654 : first_neighbor_list => neighbor_list_set%first_neighbor_list
911 :
912 8951654 : END FUNCTION first_list
913 :
914 : ! **************************************************************************************************
915 : !> \brief Return a pointer to the first neighbor node of a neighbor list.
916 : !> \param neighbor_list ...
917 : !> \return ...
918 : !> \date 23.06.2000,
919 : !> \author MK
920 : !> \version 1.0
921 : ! **************************************************************************************************
922 20758586 : FUNCTION first_node(neighbor_list) RESULT(first_neighbor_node)
923 :
924 : TYPE(neighbor_list_type), POINTER :: neighbor_list
925 : TYPE(neighbor_node_type), POINTER :: first_neighbor_node
926 :
927 20758586 : first_neighbor_node => neighbor_list%first_neighbor_node
928 :
929 20758586 : END FUNCTION first_node
930 :
931 : ! **************************************************************************************************
932 : !> \brief Return the requested data of a neighbor list.
933 : !> \param neighbor_list ...
934 : !> \param atom ...
935 : !> \param nnode ...
936 : !> \date 13.09.2000
937 : !> \author MK
938 : !> \version 1.0
939 : ! **************************************************************************************************
940 22546285 : SUBROUTINE get_neighbor_list(neighbor_list, atom, nnode)
941 :
942 : TYPE(neighbor_list_type), POINTER :: neighbor_list
943 : INTEGER, INTENT(OUT), OPTIONAL :: atom, nnode
944 :
945 22546285 : IF (ASSOCIATED(neighbor_list)) THEN
946 :
947 22546285 : IF (PRESENT(atom)) atom = neighbor_list%atom
948 22546285 : IF (PRESENT(nnode)) nnode = neighbor_list%nnode
949 :
950 : ELSE
951 :
952 0 : CPABORT("The requested neighbor list is not associated")
953 :
954 : END IF
955 :
956 22546285 : END SUBROUTINE get_neighbor_list
957 :
958 : ! **************************************************************************************************
959 : !> \brief Return the components of a neighbor list set.
960 : !> \param neighbor_list_set ...
961 : !> \param nlist ...
962 : !> \param symmetric ...
963 : !> \date 10.11.2000
964 : !> \author MK
965 : !> \version 1.0
966 : ! **************************************************************************************************
967 12153775 : SUBROUTINE get_neighbor_list_set(neighbor_list_set, nlist, symmetric)
968 :
969 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
970 : INTEGER, INTENT(OUT), OPTIONAL :: nlist
971 : LOGICAL, INTENT(OUT), OPTIONAL :: symmetric
972 :
973 12153775 : IF (ASSOCIATED(neighbor_list_set)) THEN
974 :
975 12153775 : IF (PRESENT(nlist)) nlist = neighbor_list_set%nlist
976 12153775 : IF (PRESENT(symmetric)) symmetric = neighbor_list_set%symmetric
977 :
978 : ELSE
979 :
980 0 : CPABORT("The requested neighbor list set is not associated")
981 :
982 : END IF
983 :
984 12153775 : END SUBROUTINE get_neighbor_list_set
985 :
986 : ! **************************************************************************************************
987 : !> \brief Return the components of the first neighbor list set.
988 : !> \param neighbor_list_sets ...
989 : !> \param nlist ...
990 : !> \param symmetric ...
991 : !> \date 07.2014
992 : !> \author JGH
993 : !> \version 1.0
994 : ! **************************************************************************************************
995 3236347 : SUBROUTINE get_neighbor_list_set_p(neighbor_list_sets, nlist, symmetric)
996 :
997 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
998 : POINTER :: neighbor_list_sets
999 : INTEGER, INTENT(OUT), OPTIONAL :: nlist
1000 : LOGICAL, INTENT(OUT), OPTIONAL :: symmetric
1001 :
1002 : INTEGER :: i
1003 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
1004 :
1005 3236347 : IF (ASSOCIATED(neighbor_list_sets)) THEN
1006 :
1007 3236347 : NULLIFY (neighbor_list_set)
1008 3236391 : DO i = 1, SIZE(neighbor_list_sets)
1009 3236391 : neighbor_list_set => neighbor_list_sets(i)%neighbor_list_set
1010 3236391 : IF (ASSOCIATED(neighbor_list_set)) EXIT
1011 : END DO
1012 :
1013 3236347 : IF (ASSOCIATED(neighbor_list_set)) THEN
1014 3236347 : IF (PRESENT(nlist)) nlist = neighbor_list_set%nlist
1015 3236347 : IF (PRESENT(symmetric)) symmetric = neighbor_list_set%symmetric
1016 : ELSE
1017 : CALL cp_abort(__LOCATION__, "No neighbor list set is associated. "// &
1018 0 : "Did you specify *all* required basis-sets, eg. for ADMM?")
1019 : END IF
1020 :
1021 : ELSE
1022 :
1023 0 : CPABORT("The requested neighbor list sets are not associated")
1024 :
1025 : END IF
1026 :
1027 3236347 : END SUBROUTINE get_neighbor_list_set_p
1028 :
1029 : ! **************************************************************************************************
1030 : !> \brief Return the requested data of a neighbor node.
1031 : !> \param neighbor_node ...
1032 : !> \param neighbor ...
1033 : !> \param cell ...
1034 : !> \param r ...
1035 : !> \date 23.06.2000
1036 : !> \author MK
1037 : !> \version 1.0
1038 : ! **************************************************************************************************
1039 3414517137 : SUBROUTINE get_neighbor_node(neighbor_node, neighbor, cell, r)
1040 :
1041 : TYPE(neighbor_node_type), POINTER :: neighbor_node
1042 : INTEGER, INTENT(OUT), OPTIONAL :: neighbor
1043 : INTEGER, DIMENSION(3), INTENT(OUT), OPTIONAL :: cell
1044 : REAL(dp), DIMENSION(3), INTENT(OUT), OPTIONAL :: r
1045 :
1046 3414517137 : IF (ASSOCIATED(neighbor_node)) THEN
1047 3414517137 : IF (PRESENT(neighbor)) neighbor = neighbor_node%neighbor
1048 5460544093 : IF (PRESENT(r)) r(:) = neighbor_node%r(:)
1049 4285373389 : IF (PRESENT(cell)) cell(:) = neighbor_node%cell(:)
1050 : ELSE
1051 0 : CPABORT("The requested neighbor node is not associated")
1052 : END IF
1053 :
1054 3414517137 : END SUBROUTINE get_neighbor_node
1055 :
1056 : ! **************************************************************************************************
1057 : !> \brief Initialize a neighbor list set. Nothing is (de)allocated here.
1058 : !> This routine is also used to prepare a neighbor list set for
1059 : !> overwriting.
1060 : !> \param neighbor_list_set ...
1061 : !> \param symmetric ...
1062 : !> \date 20.09.2002
1063 : !> \author MK
1064 : !> \version 1.0
1065 : ! **************************************************************************************************
1066 605635 : SUBROUTINE init_neighbor_list_set(neighbor_list_set, symmetric)
1067 :
1068 : TYPE(neighbor_list_set_type), POINTER :: neighbor_list_set
1069 : LOGICAL, INTENT(IN) :: symmetric
1070 :
1071 605635 : IF (ASSOCIATED(neighbor_list_set)) THEN
1072 :
1073 : ! *** Initialize the pointers to the last neighbor list ***
1074 605635 : NULLIFY (neighbor_list_set%last_neighbor_list)
1075 :
1076 : ! *** Initialize the neighbor list counter ***
1077 605635 : neighbor_list_set%nlist = 0
1078 :
1079 : ! *** Initialize the neighbor list build properties
1080 605635 : neighbor_list_set%symmetric = symmetric
1081 :
1082 : ELSE
1083 :
1084 0 : CPABORT("The requested neighbor list set is not associated")
1085 :
1086 : END IF
1087 :
1088 605635 : END SUBROUTINE init_neighbor_list_set
1089 :
1090 : ! **************************************************************************************************
1091 : !> \brief releases an array of neighbor_list_sets
1092 : !> \param nlists ...
1093 : !> \author Ole Schuett
1094 : ! **************************************************************************************************
1095 454243 : SUBROUTINE release_neighbor_list_sets(nlists)
1096 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1097 : POINTER :: nlists
1098 :
1099 : INTEGER :: i
1100 :
1101 454243 : IF (ASSOCIATED(nlists)) THEN
1102 820080 : DO i = 1, SIZE(nlists)
1103 820080 : CALL deallocate_neighbor_list_set(nlists(i)%neighbor_list_set)
1104 : END DO
1105 154551 : IF (ASSOCIATED(nlists(1)%nlist_task)) THEN
1106 154551 : DEALLOCATE (nlists(1)%nlist_task)
1107 : END IF
1108 154551 : DEALLOCATE (nlists)
1109 : END IF
1110 454243 : END SUBROUTINE release_neighbor_list_sets
1111 :
1112 0 : END MODULE qs_neighbor_list_types
|