(git:374b731)
Loading...
Searching...
No Matches
util.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief All kind of helpful little routines
10!> \par History
11!> none
12!> \author CJM & JGH
13! **************************************************************************************************
14MODULE util
15 USE cp_array_sort, ONLY: cp_1d_i4_sort,&
19 USE kinds, ONLY: dp
20
21 IMPLICIT NONE
22
23 PRIVATE
24 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'util'
25 PUBLIC :: sort, &
26 get_limit, &
27 locate, &
30
31 INTERFACE sort
33 sort_cv, sort_im, sort_cm
34 END INTERFACE
35
36 INTERFACE sort_unique
37 MODULE PROCEDURE sort_unique1
38 END INTERFACE
39
40 INTERFACE find_boundary
41 MODULE PROCEDURE find_boundary1, find_boundary2
42 END INTERFACE
43
44CONTAINS
45
46! **************************************************************************************************
47!> \brief Purpose: Given an array array(1:n), and given a value x, a value x_index
48!> is returned which is the index value of the array element equal
49!> to the value x: x = array(x_index)
50!> The array must be monotonic increasing.
51!> x_index = 0 is returned, if no array element equal to the value
52!> of x was found.
53!> \param array ...
54!> \param x ...
55!> \return ...
56!> \par History
57!> Derived from the locate function described in
58!> Numerical Recipes in Fortran 90 (09.01.2004,MK)
59! **************************************************************************************************
60 PURE FUNCTION locate(array, x) RESULT(x_index)
61 INTEGER, DIMENSION(:), INTENT(IN) :: array
62 INTEGER, INTENT(IN) :: x
63 INTEGER :: x_index
64
65 INTEGER :: jl, jm, ju, n
66
67 x_index = 0
68
69 IF (x < array(1)) RETURN
70 n = SIZE(array)
71 IF (x > array(n)) RETURN
72 jl = 0
73 ju = n + 1
74 DO WHILE (ju - jl > 1)
75 jm = (ju + jl)/2
76 IF (x >= array(jm)) THEN
77 jl = jm
78 ELSE
79 ju = jm
80 END IF
81 END DO
82 IF (x == array(jl)) x_index = jl
83 END FUNCTION locate
84
85! **************************************************************************************************
86!> \brief Sorts and returns a logical that checks if all elements are unique
87!> \param arr ...
88!> \param unique ...
89!> \par History
90!> Teodoro Laino - Zurich University [tlaino] 04.2007
91! **************************************************************************************************
92 SUBROUTINE sort_unique1(arr, unique)
93 INTEGER, DIMENSION(:), INTENT(INOUT) :: arr
94 LOGICAL, INTENT(OUT) :: unique
95
96 INTEGER :: i, n
97 INTEGER, ALLOCATABLE, DIMENSION(:) :: wrk
98
99 n = SIZE(arr)
100 unique = .true.
101 ALLOCATE (wrk(n))
102 CALL sort(arr, n, wrk)
103 DO i = 2, n
104 IF (arr(i) == arr(i - 1)) THEN
105 unique = .false.
106 EXIT
107 END IF
108 END DO
109 DEALLOCATE (wrk)
110 END SUBROUTINE sort_unique1
111
112! **************************************************************************************************
113!> \brief Sorts an array of strings
114!> \param arr ...
115!> \param n ...
116!> \param index ...
117!> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
118! **************************************************************************************************
119 SUBROUTINE sort_cv(arr, n, index)
120 INTEGER, INTENT(IN) :: n
121 CHARACTER(LEN=*), INTENT(INOUT) :: arr(1:n)
122 INTEGER, INTENT(OUT) :: INDEX(1:n)
123
124 INTEGER :: i, j, max_length
125 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: entries
126
127 max_length = 0
128 DO i = 1, n
129 max_length = max(max_length, len_trim(arr(i)))
130 END DO
131 ALLOCATE (entries(max_length, SIZE(arr)))
132 DO i = 1, n
133 DO j = 1, len_trim(arr(i))
134 entries(j, i) = ichar(arr(i) (j:j))
135 END DO
136 IF (j <= max_length) THEN
137 entries(j:max_length, i) = ichar(" ")
138 END IF
139 END DO
140 CALL sort_im(entries, istart=1, iend=n, j=1, jsize=max_length, index=index)
141 ! Recover string once ordered
142 DO i = 1, n
143 DO j = 1, max_length
144 arr(i) (j:j) = char(entries(j, i))
145 END DO
146 END DO
147 DEALLOCATE (entries)
148 END SUBROUTINE sort_cv
149
150! **************************************************************************************************
151!> \brief Sorts a multiple arrays M(j,i), ordering iteratively over i with fixed j
152!> \param matrix ...
153!> \param istart ...
154!> \param iend ...
155!> \param j ...
156!> \param jsize ...
157!> \param index ...
158!> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
159! **************************************************************************************************
160 RECURSIVE SUBROUTINE sort_im(matrix, istart, iend, j, jsize, index)
161 INTEGER, DIMENSION(:, :), INTENT(INOUT) :: matrix
162 INTEGER, INTENT(IN) :: istart, iend, j, jsize
163 INTEGER, DIMENSION(:), INTENT(INOUT) :: index
164
165
166 INTEGER :: item
167 INTEGER, ALLOCATABLE, DIMENSION(:) :: work, work2
168 INTEGER :: i, ind, isize, k, kend, kstart
169 INTEGER, ALLOCATABLE, DIMENSION(:) :: bck_index, tmp_index
170
171 isize = iend - istart + 1
172 ! Initialize the INDEX array only for the first row..
173 IF (j == 1) THEN
174 DO i = 1, isize
175 index(i) = i
176 ENDDO
177 END IF
178
179 ! Allocate scratch arrays
180 ALLOCATE (work(isize), work2(isize), tmp_index(isize), bck_index(isize))
181 ind = 0
182 DO i = istart, iend
183 ind = ind + 1
184 work(ind) = matrix(j, i)
185 bck_index(ind) = index(i)
186 END DO
187
188 ! Ordering row (j) interval istart..iend
189 CALL sort(work, isize, tmp_index)
190
191 ! Copy into global INDEX array with a proper mapping
192 ind = 0
193 DO i = istart, iend
194 ind = ind + 1
195 index(i) = bck_index(tmp_index(ind))
196 matrix(j, i) = work(ind)
197 END DO
198
199 ! Reorder the rest of the array according the present reordering
200 DO k = j + 1, jsize
201 ind = 0
202 DO i = istart, iend
203 ind = ind + 1
204 work2(ind) = matrix(k, i)
205 END DO
206 ind = 0
207 DO i = istart, iend
208 ind = ind + 1
209 matrix(k, i) = work2(tmp_index(ind))
210 END DO
211 END DO
212
213 ! There are more rows to order..
214 IF (j < jsize) THEN
215 kstart = istart
216 item = work(1)
217 ind = 0
218 DO i = istart, iend
219 ind = ind + 1
220 IF (item /= work(ind)) THEN
221 kend = i - 1
222 IF (kstart /= kend) THEN
223 CALL sort(matrix, kstart, kend, j + 1, jsize, index)
224 END IF
225 item = work(ind)
226 kstart = i
227 END IF
228 END DO
229 kend = i - 1
230 IF (kstart /= kend) THEN
231 CALL sort(matrix, kstart, kend, j + 1, jsize, index)
232 END IF
233 END IF
234 DEALLOCATE (work, work2, tmp_index, bck_index)
235
236 END SUBROUTINE sort_im
237! **************************************************************************************************
238!> \brief Sorts a multiple arrays M(j,i), ordering iteratively over i with fixed j
239!> \param matrix ...
240!> \param istart ...
241!> \param iend ...
242!> \param j ...
243!> \param jsize ...
244!> \param index ...
245!> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
246! **************************************************************************************************
247 RECURSIVE SUBROUTINE sort_cm(matrix, istart, iend, j, jsize, index)
248 CHARACTER(LEN=*), DIMENSION(:, :), INTENT(INOUT) :: matrix
249 INTEGER, INTENT(IN) :: istart, iend, j, jsize
250 INTEGER, DIMENSION(:), INTENT(INOUT) :: index
251
252
253 CHARACTER(LEN=LEN(matrix)) :: item
254 CHARACTER(LEN=LEN(matrix)), ALLOCATABLE, DIMENSION(:) :: work, work2
255 INTEGER :: i, ind, isize, k, kend, kstart
256 INTEGER, ALLOCATABLE, DIMENSION(:) :: bck_index, tmp_index
257
258 isize = iend - istart + 1
259 ! Initialize the INDEX array only for the first row..
260 IF (j == 1) THEN
261 DO i = 1, isize
262 index(i) = i
263 ENDDO
264 END IF
265
266 ! Allocate scratch arrays
267 ALLOCATE (work(isize), work2(isize), tmp_index(isize), bck_index(isize))
268 ind = 0
269 DO i = istart, iend
270 ind = ind + 1
271 work(ind) = matrix(j, i)
272 bck_index(ind) = index(i)
273 END DO
274
275 ! Ordering row (j) interval istart..iend
276 CALL sort(work, isize, tmp_index)
277
278 ! Copy into global INDEX array with a proper mapping
279 ind = 0
280 DO i = istart, iend
281 ind = ind + 1
282 index(i) = bck_index(tmp_index(ind))
283 matrix(j, i) = work(ind)
284 END DO
285
286 ! Reorder the rest of the array according the present reordering
287 DO k = j + 1, jsize
288 ind = 0
289 DO i = istart, iend
290 ind = ind + 1
291 work2(ind) = matrix(k, i)
292 END DO
293 ind = 0
294 DO i = istart, iend
295 ind = ind + 1
296 matrix(k, i) = work2(tmp_index(ind))
297 END DO
298 END DO
299
300 ! There are more rows to order..
301 IF (j < jsize) THEN
302 kstart = istart
303 item = work(1)
304 ind = 0
305 DO i = istart, iend
306 ind = ind + 1
307 IF (item /= work(ind)) THEN
308 kend = i - 1
309 IF (kstart /= kend) THEN
310 CALL sort(matrix, kstart, kend, j + 1, jsize, index)
311 END IF
312 item = work(ind)
313 kstart = i
314 END IF
315 END DO
316 kend = i - 1
317 IF (kstart /= kend) THEN
318 CALL sort(matrix, kstart, kend, j + 1, jsize, index)
319 END IF
320 END IF
321 DEALLOCATE (work, work2, tmp_index, bck_index)
322
323 END SUBROUTINE sort_cm
324
325! **************************************************************************************************
326!> \brief divide m entries into n parts, return size of part me
327!> \param m ...
328!> \param n ...
329!> \param me ...
330!> \return ...
331! **************************************************************************************************
332 PURE FUNCTION get_limit(m, n, me) RESULT(nlim)
333 INTEGER, INTENT(IN) :: m, n, me
334 INTEGER :: nlim(2)
335
336 INTEGER :: nl, nu
337 REAL(kind=dp) :: part
338
339 part = real(m, kind=dp)/real(n, kind=dp)
340 nl = nint(real(me, kind=dp)*part) + 1
341 nu = nint(real(me + 1, kind=dp)*part)
342 nlim(1) = max(1, nl)
343 nlim(2) = min(m, nu)
344
345 END FUNCTION get_limit
346
347! **************************************************************************************************
348!> \brief finds boundary where element search starts and ends in a 1D array
349!> array1: XXXXXAAAAAAAAAXXDGFSFGWDDDDDDDAAAWE
350!> | |
351!> start end (searching for A)
352!> \param num_array ...
353!> \param ntot ...
354!> \param first ...
355!> \param last ...
356!> \param search ...
357! **************************************************************************************************
358 PURE SUBROUTINE find_boundary1(num_array, ntot, first, last, search)
359 INTEGER, POINTER :: num_array(:)
360 INTEGER, INTENT(IN) :: ntot
361 INTEGER, INTENT(OUT) :: first, last
362 INTEGER, INTENT(IN) :: search
363
364 INTEGER :: i
365 LOGICAL :: found
366
367 found = .false.
368 first = 0
369 last = ntot
370
371 DO i = 1, ntot
372 IF (num_array(i) == search) THEN
373 IF (.NOT. found) THEN
374 first = i
375 END IF
376 found = .true.
377 ELSE
378 IF (found) THEN
379 last = i - 1
380 EXIT
381 END IF
382 found = .false.
383 END IF
384 END DO
385
386 END SUBROUTINE find_boundary1
387
388! **************************************************************************************************
389!> \brief finds boundary where element search1 starts and ends in array1 checking
390!> at the same time search2 in array2
391!> array1: XXXXXAAAAAAAAAXXDGFSFGWDDDDDDDAAAWE
392!> array2: XXXXASDEYYYYASDEFAAAARGASGASRGAWRRR
393!> | |
394!> start end (searching for A and Y)
395!> \param num_array1 ...
396!> \param num_array2 ...
397!> \param ntot ...
398!> \param first ...
399!> \param last ...
400!> \param search1 ...
401!> \param search2 ...
402! **************************************************************************************************
403 PURE SUBROUTINE find_boundary2(num_array1, num_array2, ntot, first, last, search1, search2)
404 INTEGER, POINTER :: num_array1(:), num_array2(:)
405 INTEGER, INTENT(IN) :: ntot
406 INTEGER, INTENT(OUT) :: first, last
407 INTEGER, INTENT(IN) :: search1, search2
408
409 INTEGER :: i, tfirst, tlast
410 LOGICAL :: found
411
412 found = .false.
413 first = 0
414 last = ntot
415
416 CALL find_boundary(num_array1, ntot, tfirst, tlast, search1)
417 last = tlast
418 DO i = tfirst, tlast
419 IF (num_array2(i) == search2) THEN
420 IF (.NOT. found) THEN
421 first = i
422 END IF
423 found = .true.
424 ELSE
425 IF (found) THEN
426 last = i - 1
427 EXIT
428 END IF
429 found = .false.
430 END IF
431 END DO
432
433 END SUBROUTINE find_boundary2
434
435END MODULE util
Routine for sorting an array.
subroutine, public cp_1d_i4_sort(arr, n, indices)
Sorts an array inplace using a combination of merge- and bubble-sort. It also returns the indices,...
subroutine, public cp_1d_i8_sort(arr, n, indices)
Sorts an array inplace using a combination of merge- and bubble-sort. It also returns the indices,...
subroutine, public cp_1d_s_sort(arr, n, indices)
Sorts an array inplace using a combination of merge- and bubble-sort. It also returns the indices,...
subroutine, public cp_1d_r_sort(arr, n, indices)
Sorts an array inplace using a combination of merge- and bubble-sort. It also returns the indices,...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
All kind of helpful little routines.
Definition util.F:14
pure integer function, public locate(array, x)
Purpose: Given an array array(1:n), and given a value x, a value x_index is returned which is the ind...
Definition util.F:61
pure integer function, dimension(2), public get_limit(m, n, me)
divide m entries into n parts, return size of part me
Definition util.F:333