Neko 1.99.3
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
utils.f90
Go to the documentation of this file.
1! Copyright (c) 2019-2021, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
35module utils
36 use, intrinsic :: iso_fortran_env, only : error_unit, output_unit
37 use iso_c_binding
38 implicit none
39 private
40
41 integer, parameter :: neko_fname_len = 1024
42 integer, parameter :: neko_varname_len = 256
43
44 interface neko_error
45 module procedure neko_error_plain, neko_error_msg
46 end interface neko_error
47
54
55 interface
56 function c_mkdir(path, mode) bind(C, name="mkdir")
57 import :: c_char, c_int
58 character(kind=c_char), dimension(*) :: path
59 integer(c_int), value :: mode
60 integer(c_int) :: c_mkdir
61 end function c_mkdir
62 end interface
63
64contains
65
67 pure function filename_suffix_pos(fname) result(suffix_pos)
68 character(len=*), intent(in) :: fname
69 integer :: suffix_pos
70 suffix_pos = scan(trim(fname), '.', back = .true.)
71 end function filename_suffix_pos
72
74 pure function filename_tslash_pos(fname) result(tslash_pos)
75 character(len=*), intent(in) :: fname
76 integer :: tslash_pos
77 tslash_pos = scan(trim(fname), '/', back = .true.)
78 end function filename_tslash_pos
79
81 subroutine filename_path(fname, path)
82 character(len=*), intent(in) :: fname
83 character(len=*), intent(out) :: path
84 integer :: tslash_pos
85
86 tslash_pos = filename_tslash_pos(fname)
87 if (tslash_pos .gt. 0) then
88 path = trim(fname(1:tslash_pos))
89 else
90 path = './'
91 end if
92
93 end subroutine filename_path
94
96 subroutine filename_name(fname, name)
97 character(len=*), intent(in) :: fname
98 character(len=*), intent(out) :: name
99 integer :: tslash_pos, suffix_pos, start, end
100
101 tslash_pos = filename_tslash_pos(fname)
102 suffix_pos = filename_suffix_pos(fname)
103 if (tslash_pos .eq. 0) then
104 start = 1
105 else
106 start = tslash_pos + 1
107 end if
108 if (suffix_pos .eq. 0) then
109 end = len_trim(fname)
110 else
111 end = suffix_pos - 1
112 end if
113 name = trim(fname(start:end))
114 end subroutine filename_name
115
117 subroutine filename_suffix(fname, suffix)
118 character(len=*) :: fname
119 character(len=*) :: suffix
120 suffix = trim(fname(filename_suffix_pos(fname) + 1:len_trim(fname)))
121 end subroutine filename_suffix
122
124 subroutine filename_split(fname, path, name, suffix)
125 character(len=*), intent(in) :: fname
126 character(len=*), intent(out) :: path, name, suffix
127 integer :: tslash_pos, suffix_pos
128
129 tslash_pos = filename_tslash_pos(fname)
130 suffix_pos = filename_suffix_pos(fname)
131
132 if (tslash_pos .gt. 0) then
133 path = trim(fname(1:tslash_pos))
134 else
135 path = './'
136 end if
137
138 if (suffix_pos .gt. 0) then
139 name = trim(fname(tslash_pos + 1:suffix_pos - 1))
140 suffix = trim(fname(suffix_pos:len_trim(fname)))
141 else
142 name = trim(fname(tslash_pos + 1:len_trim(fname)))
143 suffix = ''
144 end if
145
146 end subroutine filename_split
147
149 subroutine filename_chsuffix(fname, new_fname, new_suffix)
150 character(len=*) :: fname
151 character(len=*) :: new_fname
152 character(len=*) :: new_suffix
153 integer :: suffix_pos
154
155 suffix_pos = filename_suffix_pos(fname)
156 new_fname = trim(fname(1:suffix_pos))//new_suffix
157
158 end subroutine filename_chsuffix
159
167 recursive subroutine mkdir(path, mode)
168 character(len=*), intent(in) :: path
169 integer, intent(in), optional :: mode
170 integer :: slash_pos, i, path_len
171 character(kind=c_char), allocatable :: c_path(:)
172 integer(c_int) :: dir_mode, ierr
173
174 if (present(mode)) then
175 dir_mode = int(mode, kind=c_int)
176 else
177 dir_mode = int(o'777', kind=c_int)
178 end if
179
180 slash_pos = scan(path, '/', back = .true.)
181 if (slash_pos .gt. 0) then
182 call mkdir(trim(path(1:slash_pos-1)), dir_mode)
183 end if
184
185 path_len = len_trim(path)
186 allocate(c_path(path_len + 1))
187 do i = 1, path_len
188 c_path(i) = path(i:i)
189 end do
190 c_path(path_len + 1) = c_null_char
191
192 ierr = c_mkdir(c_path, dir_mode)
193 deallocate(c_path)
194 end subroutine mkdir
195
202 function extract_fld_file_index(fld_filename, default_index) result(index)
203 character(len=*), intent(in) :: fld_filename
204 integer, intent(in) :: default_index
205
206 character(len=80) :: suffix
207 integer :: index, fpos, i
208 logical :: valid
209
210 call filename_suffix(fld_filename, suffix)
211
212 valid = .true.
213
214 ! This value will be modified when reading the file name extension
215 ! e.g. "field0.f00035" will set sample_idx = 35
216 index = default_index
217
218 !
219 ! Try to extract the index of the field file from the suffix "fxxxxx"
220 !
221 fpos = scan(trim(suffix), 'f')
222 if (fpos .eq. 1) then
223 ! Make sure that the suffix only contains integers from 0 to 9
224 do i = 2, len(trim(suffix))
225 if (.not. (iachar(suffix(i:i)) >= iachar('0') &
226 .and. iachar(suffix(i:i)) <= iachar('9'))) then
227 valid = .false.
228 end if
229 end do
230 else
231 valid = .false.
232 end if
233
234 ! Must be exactly 6 characters long, i.e. an 'f' with 5 integers after
235 if (len(trim(suffix)) .ne. 6) valid = .false.
236
237 if (valid) read (suffix(2:), "(I5.5)") index
238
239 end function extract_fld_file_index
240
244 function split_string(string, delimiter) result(split_str)
245 character(len=*) :: string
246 character(len=*) :: delimiter
247 character(len=100), allocatable :: split_str(:)
248 integer :: length, i, i2, offset, j
249 i = 0
250 offset = 1
251 length = 1
252 if (len(trim(string)) .eq. 0) then
253 allocate(split_str(1))
254 split_str(1) = trim(string)
255 return
256 end if
257 do while (.true.)
258 i = scan(string(offset:), delimiter, back = .false.)
259 if (i .eq. 0) exit
260 length = length + 1
261 offset = offset + i
262 end do
263
264 allocate(split_str(length))
265 i = 0
266 j = 1
267 offset = 1
268 do while (.true.)
269 i2 = scan(trim(string(offset:)), delimiter, back = .false.)
270 if (i2 .eq. 0) then
271 split_str(j) = trim(string(offset:))
272 exit
273 end if
274 split_str(j) = trim(string(offset:offset+i2-2))
275 offset = offset+i2
276 j = j + 1
277 end do
278 end function split_string
279
282 pure function linear_index(i, j, k, l, lx, ly, lz) result(index)
283 integer, intent(in) :: i, j, k, l, lx, ly, lz
284 integer :: index
285
286 index = (i + lx * ((j - 1) + ly * ((k - 1) + lz * ((l - 1)))))
287 end function linear_index
288
291 pure function nonlinear_index(linear_index, lx, ly, lz) result(index)
292 integer, intent(in) :: linear_index, lx, ly, lz
293 integer :: index(4)
294 integer :: lin_idx
295 lin_idx = linear_index -1
296 index(4) = lin_idx/(lx*ly*lz)
297 index(3) = (lin_idx-(lx*ly*lz)*index(4))/(lx*ly)
298 index(2) = (lin_idx-(lx*ly*lz)*index(4)-(lx*ly)*index(3))/lx
299 index(1) = (lin_idx-(lx*ly*lz)*index(4)-(lx*ly)*index(3)-lx*index(2))
300 index(1) = index(1) + 1
301 index(2) = index(2) + 1
302 index(3) = index(3) + 1
303 index(4) = index(4) + 1
304
305 end function nonlinear_index
306
307 pure function index_is_on_facet(i, j, k, lx, ly, lz, facet) result(is_on)
308 integer, intent(in) :: i, j, k, lx, ly, lz, facet
309 logical :: is_on
310
311 is_on = .false.
312 select case (facet)
313 case (1)
314 if (i .eq. 1) is_on = .true.
315 case (2)
316 if (i .eq. lx) is_on = .true.
317 case (3)
318 if (j .eq. 1) is_on = .true.
319 case (4)
320 if (j .eq. ly) is_on = .true.
321 case (5)
322 if (k .eq. 1) is_on = .true.
323 case (6)
324 if (k .eq. lz) is_on = .true.
325 end select
326
327 end function index_is_on_facet
328
331 subroutine neko_error_plain(error_code)
332 integer, optional :: error_code
333
334 if (present(error_code)) then
335 write(error_unit, *) '*** ERROR ***', error_code
336 error stop
337 else
338 write(error_unit, *) '*** ERROR ***'
339 error stop
340 end if
341
342 end subroutine neko_error_plain
343
346 subroutine neko_error_msg(error_msg)
347 character(len=*) :: error_msg
348 write(error_unit, *) '*** ERROR: ', trim(error_msg), ' ***'
349 error stop
350 end subroutine neko_error_msg
351
358 subroutine neko_type_error(base_type, wrong_type, known_types)
359 character(len=*), intent(in) :: base_type
360 character(len=*), intent(in) :: wrong_type
361 character(len=*), intent(in) :: known_types(:)
362 integer :: i
363
364 write(error_unit, *) '*** ERROR WHEN SELECTING TYPE ***'
365 write(error_unit, *) 'Type ', wrong_type, ' does not exist for ', base_type
366 write(error_unit, *) 'Valid types are:'
367 do i = 1, size(known_types)
368 write(error_unit, *) " ", known_types(i)
369 end do
370 error stop
371 end subroutine neko_type_error
372
373 subroutine neko_type_registration_error(base_type, wrong_type, known)
374 character(len=*), intent(in) :: base_type
375 character(len=*), intent(in) :: wrong_type
376 logical, intent(in) :: known
377
378 write(error_unit, *) '*** ERROR WHEN REGISTERING TYPE ***'
379 write(error_unit, *) 'Type name ', wrong_type, &
380 ' conflicts with and already existing ', base_type, " type"
381 if (known) then
382 write(error_unit, *) 'Please rename your custom type.'
383 else
384 write(error_unit, *) 'The already existing type is also custom.' // &
385 ' Make all custom type names unique!'
386 end if
387 error stop
388 end subroutine neko_type_registration_error
389
391 subroutine neko_warning(warning_msg)
392 character(len=*) :: warning_msg
393 write(output_unit, *) '*** WARNING: ', trim(warning_msg), ' ***'
394 end subroutine neko_warning
395
401 function concat_string_array(array, sep, prepend) result(result)
402 character(len=*), intent(in) :: array(:)
403 character(len=*), intent(in) :: sep
404 logical, intent(in) :: prepend
405 character(:), allocatable :: result
406 integer :: i
407
408 result = trim(array(1))
409 do i = 2, size(array)
410 result = result // sep // trim(array(i))
411 end do
412
413 if (prepend) then
414 result = sep // result
415 end if
416
417 end function concat_string_array
418
419end module utils
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
Utilities.
Definition utils.f90:35
integer function, public extract_fld_file_index(fld_filename, default_index)
Extracts the index of a field file. For example, "myfield.f00045" will return 45. If the suffix of th...
Definition utils.f90:203
character(:) function, allocatable, public concat_string_array(array, sep, prepend)
Concatenate an array of strings into one string with array items separated by spaces.
Definition utils.f90:402
subroutine, public neko_type_registration_error(base_type, wrong_type, known)
Definition utils.f90:374
subroutine, public filename_name(fname, name)
Extract the base name of a file (without path and suffix)
Definition utils.f90:97
character(len=100) function, dimension(:), allocatable, public split_string(string, delimiter)
Split a string based on delimiter (tokenizer) OBS: very hacky, this should really be improved,...
Definition utils.f90:245
pure logical function, public index_is_on_facet(i, j, k, lx, ly, lz, facet)
Definition utils.f90:308
subroutine neko_error_msg(error_msg)
Reports an error and stops execution.
Definition utils.f90:347
pure integer function, public linear_index(i, j, k, l, lx, ly, lz)
Compute the address of a (i,j,k,l) array with sizes (1:lx, 1:ly, 1:lz, :)
Definition utils.f90:283
integer, parameter, public neko_fname_len
Definition utils.f90:41
subroutine, public filename_split(fname, path, name, suffix)
Extract file name components.
Definition utils.f90:125
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:392
subroutine, public filename_chsuffix(fname, new_fname, new_suffix)
Change a filename's suffix.
Definition utils.f90:150
subroutine, public filename_suffix(fname, suffix)
Extract a filename's suffix.
Definition utils.f90:118
subroutine, public neko_type_error(base_type, wrong_type, known_types)
Reports an error allocating a type for a particular base pointer class.
Definition utils.f90:359
recursive subroutine, public mkdir(path, mode)
Recursively create a directory and all parent directories if they do not exist. This should be safer ...
Definition utils.f90:168
integer, parameter, public neko_varname_len
Definition utils.f90:42
pure integer function, public filename_tslash_pos(fname)
Find position (in the string) of a filename's trailing slash.
Definition utils.f90:75
subroutine neko_error_plain(error_code)
Reports an error and stops execution.
Definition utils.f90:332
pure integer function, public filename_suffix_pos(fname)
Find position (in the string) of a filename's suffix.
Definition utils.f90:68
subroutine, public filename_path(fname, path)
Extract the path to a file.
Definition utils.f90:82