Globals Library 1.0
Loading...
Searching...
No Matches
modGlobals.f90
Go to the documentation of this file.
1!-------------------------------------------------------------
2! Define global vars
3!
4! err numbers:
5! errno = [0:1][01-10] I/O errors (file existence etc...)
6! = [0:1][11-20] input errors (reads)
7! = [0:1][21-30] output errors (writes)
8! = [0:1][31-40] alloc errors
9! = [0:1][41-50] dealloc errors
10! = [0:1][51-60] vtk libray errors
11!-------------------------------------------------------------
12module globals
13
15
16 implicit none
17
18 !> File or directory does not exist
19 integer, parameter :: wrn_io = 1
20 !> Error in input/outour parameter
21 integer, parameter :: wrn_val = 3
22 !> Error reading file
23 integer, parameter :: wrn_read = 11
24 !> Error writing file
25 integer, parameter :: wrn_write = 21
26 !> Error in input parameter
27 integer, parameter :: wrn_inp = 13
28 !> Error in outour parameter
29 integer, parameter :: wrn_out = 23
30 !> File or directory does not exist
31 integer, parameter :: err_io = 101
32 !> Error in input parameter
33 integer, parameter :: err_inp = 111
34 !> Error in outour parameter
35 integer, parameter :: err_out = 121
36 !> Error allocation failed
37 integer, parameter :: err_alloc = 131
38 !> Error deallocation failed
39 integer, parameter :: err_dealloc = 141
40 !> Error VTK library
41 integer, parameter :: err_vtk = 151
42 !> Error reading file
43 integer, parameter :: err_read = 161
44 !> Error writing file
45 integer, parameter :: err_write = 171
46 !> Error in parameter value
47 integer, parameter :: err_val = 201
48
49 type, public :: file
50 !> Logical flag to check if file exists
51 logical :: exist = .false.
52 !> I/O unit number
53 integer :: lun
54 !> File or directory name
55 character(len=256) :: fn
56 !> Local file or directory name
57 character(len=256) :: fnloc
58 ! integer(hid_t) :: hdf5_id=0 !< ID numbe for corresponding dataset in h5df
59 contains
60 !> Static constructor for `globals::file`
61 procedure, public, pass :: init => fn_init
62 !> Static destructor for `globals::file`
63 procedure, public, pass :: kill => fn_kill
64 !> Info procedure for `globals::file`
65 procedure, public, pass :: info => fn_print
66 !> Get directory name
67 procedure, public, nopass :: get_dirname
68 end type file
69
70contains
71
72 !>-------------------------------------------------------------
73 !> @brief Handle and write alert I/O warnings and errors
74 !> @details Error number convention:
75 !> * 0 < errno <= 100 -> **warning**: execution continues
76 !> * errno > 100 -> **severe**: execution terminates
77 !>
78 !> @param[in] lun: I/O unit number for output of error messages
79 !> @param[in] errno: error number
80 !> @param[in] call_proc: name of the procedure where the error occured
81 !> @param[in] add_msg: additional message to be printed (optional)
82 !> @param[in] add_int: additional integer to be printed as
83 !> string in the message (optional)
84 !> @return (logical) `.true.` if execution continues
85 !> (obviously no return otherwise as execution stops)
86 !<-------------------------------------------------------------
87 function ioerr(lun, errno, call_proc, add_msg, add_int) result(rc)
88 implicit none
89 integer, intent(in) :: lun
90 integer, intent(in) :: errno
91 character(len=*), intent(in) :: call_proc
92 character(len=*), intent(in), optional :: add_msg
93 integer, intent(in), optional :: add_int
94 logical :: rc
95 ! local vars
96 character(len=256) :: msg
97 integer :: int
98
99 if (present(add_msg)) then
100 msg = trim(add_msg)
101 if (present(add_int)) then
102 int = add_int
103 else
104 int = 0
105 end if
106 else
107 msg = ''
108 int = 0
109 end if
110 write (lun, *) ''
111 write (lun, *) ' *************'
112 if (errno .gt. 100) then
113 write (lun, fmt=100) ' SEVERE ERROR:'
114 write (lun, fmt=101) ' in procedure: ', trim(call_proc)
115 write (lun, fmt=101) trim(errmsg(errno, trim(msg), int))
116 stop 'EXECUTION TERMINATED IN PROC IOerr'
117 else if (errno .gt. 0) then
118 write (lun, fmt=100) ' WARNING ERROR:'
119 write (lun, fmt=101) 'in procedure: ', trim(call_proc)
120 write (lun, fmt=101) etb((errmsg(errno, trim(msg), int)))
121 rc = .true.
122 else
123 write (lun, fmt=100) ' IO ERROR NUMBER not found'
124 stop 'EXECUTION TERMINATED IN PROC IOerr'
125 end if
126
127100 format(1x, a, 1x, i5)
128101 format(5(1x, a))
129
130 contains
131
132 !>-------------------------------------------------------------
133 !> @brief Return message depending on input number
134 !>
135 !> @param[in] errno: error number
136 !> @param[in] addmsg: additional message to be printed
137 !> @param[in] int: to be included in msg if nonzero
138 !> @return msg: error message
139 !<-------------------------------------------------------------
140 function errmsg(errno, addmsg, addint) result(msg)
141 implicit none
142 integer, intent(in) :: errno
143 character(len=*), intent(in) :: addmsg
144 integer, intent(in) :: addint
145 character(len=256) :: msg
146 ! local vars
147 character(len=5) :: rdwr
148
149 if (addint .eq. 0) then
150 rdwr = ''
151 else
152 write (rdwr, '(i5)') addint
153 end if
154
155 select case (errno)
156 case (wrn_io) ! file/dir not found but continues execution
157 msg = 'File or Directory '//trim(addmsg)//' (unit '//rdwr//') does not exist.'
158 case (wrn_read) ! error in reading file
159 msg = 'Error Reading File '//trim(addmsg)//' (unit '//rdwr//')'
160 case (wrn_write) ! error in writing file
161 msg = 'Error Writing File '//trim(addmsg)//' (unit '//rdwr//')'
162 case (wrn_val) ! error in inputs data
163 msg = 'Error In Input/Output Parameter '//trim(addmsg)//' (info='//rdwr//')'
164 case (wrn_inp) ! error in inputs data
165 msg = 'Error In Input Parameter '//trim(addmsg)//rdwr//')'
166 case (wrn_out) ! error in output
167 msg = 'Error In Output Parameter '//trim(addmsg)//rdwr//')'
168 case (err_io) ! file/dir not found but stops execution
169 msg = 'File or Directory '//trim(addmsg)//' (unit '//rdwr//') does not exist.'
170 case (err_read) ! error reading a number in input
171 msg = ' ...error reading file '//trim(addmsg)//' (iostat='//rdwr//')'
172 case (err_write) ! error writing a number in input
173 msg = ' ...error writing file '//trim(addmsg)//' (iostat='//rdwr//')'
174 case (err_inp) ! error reading a number in input
175 msg = 'Error In Input Parameter '//trim(addmsg)//' ( '//rdwr//' )'
176 case (err_out) ! error writing a number in input
177 msg = 'Error In Output Parameter '//trim(addmsg)
178 case (err_alloc) ! error allocating an array
179 msg = ' ...alloc fail var '//trim(addmsg)//' (stat='//rdwr//')'
180 case (err_dealloc) ! error deallocating an array
181 msg = ' ...dealloc fail var '//trim(addmsg)//' (stat='//rdwr//')'
182 case (err_vtk) ! error writing vtk files
183 msg = ' ...VTK library: '//trim(addmsg)//rdwr
184 case (err_val) ! error in parameter values
185 msg = ' ...wrong parameter value: '//trim(addmsg)//rdwr
186 case default
187 msg = ' no known error number'
188 end select
189
190 end function errmsg
191
192 end function ioerr
193
194 !>-------------------------------------------------------------
195 !> @brief Transform string to upper case
196 !> @details Adapted from http://rosettacode.org/wiki/String_case#Fortran.
197 !> Original author: Clive Page
198 !>
199 !> @param[in] strin: input string
200 !> @return (char) output string
201 !<-------------------------------------------------------------
202 function to_upper(strIn) result(strOut)
203 implicit none
204 character(len=*), intent(in) :: strin
205 character(len=len(strIn)) :: strout
206 ! local vars
207 integer :: i
208
209 do i = 1, len(strin)
210 select case (strin(i:i))
211 case ("a":"z")
212 strout(i:i) = achar(iachar(strin(i:i)) - 32)
213 end select
214 end do
215
216 end function to_upper
217
218 !>-------------------------------------------------------------
219 !> @brief Transform string to lowercase case
220 !> @details Adapted from http://rosettacode.org/wiki/String_case#Fortran.
221 !> Original author: Clive Page
222 !>
223 !> @param[in] strin: input string
224 !> @return
225 !> (char) output string
226 !<-------------------------------------------------------------
227 function to_lower(strIn) result(strOut)
228 implicit none
229 character(len=*), intent(in) :: strin
230 character(len=len(strIn)) :: strout
231 ! local vars
232 integer :: i
233
234 do i = 1, len(strin)
235 select case (strin(i:i))
236 case ("A":"Z")
237 strout(i:i) = achar(iachar(strin(i:i)) + 32)
238 case default
239 strout(i:i) = strin(i:i)
240 end select
241 end do
242 end function to_lower
243
244 !>-------------------------------------------------------------
245 !> @brief Return string strin with no preceding and trailing spaces
246 !>
247 !> @param[in] strin: input string
248 !> @return (char) output string
249 !<-------------------------------------------------------------
250 function etb(strIn) result(strOut)
251 implicit none
252 character(len=*), intent(in) :: strin
253 character(len=len_trim(adjustl(strIn))) :: strout
254
255 strout = trim(adjustl(strin))
256
257 end function etb
258
259 !>-------------------------------------------------------------
260 !> @brief Erase comments from a string
261 !> @details A comment is a trailing string beginning
262 !> with one of the following characters:
263 !> * ! F90-style
264 !> * `%` TeX-style
265 !> * `#` script-bash-style
266 !>
267 !> @param[in] strin: input string
268 !> @return (char) output string
269 !<-------------------------------------------------------------
270 function erase_comment(strIn) result(strOut)
271 implicit none
272 character(len=*), intent(in) :: strin
273 character(len=len_trim(adjustl(strIn))) :: strout
274 ! local vars
275 character(len=1) :: strloc
276 integer :: i, j
277
278 do i = 1, len_trim(adjustl(strin))
279 strloc = strin(i:i)
280 if (strloc .eq. '!' .or. strloc .eq. '%' .or. strloc .eq. '#') then
281 do j = i, len_trim(adjustl(strin))
282 strout(j:j) = ' '
283 end do
284 exit
285 else
286 strout(i:i) = strloc
287 end if
288 end do
289
290 end function erase_comment
291
292 !>-------------------------------------------------------------
293 !> @brief Function that calculates vectors averages
294 !> @details Cases:
295 !> * **on edge**, between two vectors related to the nodes of an edge
296 !> * **on cell**, between three vectors related to the vertices of a triangle
297 !>
298 !> @param[in] avg_type: type of average. `0`: arithmetic average.
299 !> @param[in] vec1: vector to be averaged
300 !> @param[in] vec2: vector to be averaged
301 !> @param[in] vec3: vector to be averaged (optional)
302 !> @return real(double). dimension(3), averaged vector
303 !<-------------------------------------------------------------
304 function avg_vec3(avg_type, vecA, vecB, vecC) result(res_avg)
305 implicit none
306 integer, intent(in) :: avg_type
307 real(kind=double), intent(in) :: veca(3)
308 real(kind=double), intent(in) :: vecb(3)
309 real(kind=double), intent(in), optional :: vecc(3)
310 real(kind=double) :: res_avg(3)
311 ! local vars
312 integer :: i
313
314 if (present(vecc)) then
315 ! cell average
316 select case (avg_type)
317 case (0)
318 do i = 1, 3
319 res_avg(i) = avg_scal(avg_type, veca(i), vecb(i), vecc(i))
320 end do
321 end select
322 else
323 ! edge average
324 select case (avg_type)
325 case (0)
326 do i = 1, 3
327 res_avg(i) = avg_scal(avg_type, veca(i), vecb(i))
328 end do
329 end select
330 end if
331
332 end function avg_vec3
333
334 !>-------------------------------------------------------------
335 !> @brief Function that calculates scalar averages
336 !> @details Cases:
337 !> * **on edge**, between two vectors related to the nodes of an edge
338 !> * **on cell**, between three vectors related to the vertices of a triangle
339 !>
340 !> @param[in] avg_type: type of average. `0`: arithmetic average.
341 !> @param[in] A: scalar to be averaged
342 !> @param[in] B: scalar to be averaged
343 !> @param[in] C: scalar to be averaged (optional)
344 !> @return real(double), average
345 !<-------------------------------------------------------------
346 function avg_scal(avg_type, A, B, C) result(res_avg)
347 implicit none
348 integer, intent(in) :: avg_type
349 real(kind=double), intent(in) :: a
350 real(kind=double), intent(in) :: b
351 real(kind=double), intent(in), optional :: c
352 real(kind=double) :: res_avg
353 ! local vars
354
355 res_avg = zero
356 if (present(c)) then
357 ! cell average
358 select case (avg_type)
359 case (0)
360 res_avg = onethird*(a + b + c)
361 end select
362 else
363 ! edge average
364 select case (avg_type)
365 case (0)
366 res_avg = onehalf*(a + b)
367 end select
368 end if
369
370 end function avg_scal
371
372 !>-------------------------------------------------------------
373 !> @brief Function that calculates cross-products
374 !>
375 !> @param[in] vec1: vector
376 !> @param[in] vec2: vector
377 !> @return real(`::double`), dimension(3), vector
378 !<-------------------------------------------------------------
379 function cross(vecA, vecB) result(res_cross)
380 implicit none
381 real(kind=double), intent(in) :: veca(3)
382 real(kind=double), intent(in) :: vecb(3)
383 real(kind=double) :: res_cross(3)
384
385 res_cross(1) = veca(2)*vecb(3) - veca(3)*vecb(2)
386 res_cross(2) = veca(3)*vecb(1) - veca(1)*vecb(3)
387 res_cross(3) = veca(1)*vecb(2) - veca(2)*vecb(1)
388
389 end function cross
390
391 !>--------------------------------------------------------------
392 !> @brief Simple sort algorithm to sort in increasing order an
393 !> integer array. To be used only for small array.
394 !> Use `globals::global_heapsort` for big arrays.
395 !>
396 !> @param[in ] narray: length array to be sorted
397 !> @param[inout] array: array to be sorted
398 !<-------------------------------------------------------------
399 subroutine isort(narray, array)
400 implicit none
401 integer, intent(in) :: narray
402 integer, intent(inout) :: array(narray)
403 ! local vars
404 integer :: itemp
405 integer :: i, j, indx, isgn
406
407 if (narray .lt. 2) return
408 ! Initialize.
409 i = 0
410 indx = 0
411 isgn = 0
412 j = 0
413 do
414 call global_heapsort(narray, indx, i, j, isgn)
415 if (indx .gt. 0) then
416 ! SWAP ELEMENT
417 itemp = array(i)
418 array(i) = array(j)
419 array(j) = itemp
420 else if (indx .lt. 0) then
421 ! COMPARE (array(i) and array(j) )
422 isgn = 0
423 if (array(i) .lt. array(j)) isgn = -1
424 if (array(i) .gt. array(j)) isgn = +1
425 else if (indx .eq. 0) then
426 exit
427 end if
428 end do
429
430 end subroutine isort
431
432 !>--------------------------------------------------------------
433 !> @brief Given a sorted array, it is returned with the
434 !> list of uniques elements in the first positions.
435 !>
436 !> @param[in ] n_elements: length of the array `elements`
437 !> @param[inout] elements: sorted array
438 !> @param[inout] nunique: number of unique elements
439 !<--------------------------------------------------------------
440 subroutine unique_of_sorted(n_elements, elements, nunique)
441 implicit none
442 integer, intent(in) :: n_elements
443 integer, intent(inout) :: elements(n_elements)
444 integer, intent(inout) :: nunique
445 ! local
446 integer :: unique_index, unique_element, current_element, i
447
448 ! nothing to do
449 if (n_elements <= 1) return
450
451 unique_index = 1
452 unique_element = elements(1)
453 nunique = 1
454 do i = 2, n_elements
455 current_element = elements(i)
456 if (current_element .ne. unique_element) then
457 ! new node found. Add an moved it in the
458 ! corresponding position
459 nunique = nunique + 1
460 elements(nunique) = current_element
461 unique_element = current_element
462 end if
463 end do
464
465 end subroutine unique_of_sorted
466
467 !>--------------------------------------------------------------
468 !> @brief Check if the first array is in lexicographic order
469 !> with respect to the second
470 !>
471 !> @param[in] n: dimension of the input arrays
472 !> @param[in] a: first array of dimension `n`
473 !> @param[in] b: second array of dimension `n`
474 !> @result (logical) `.true.` if `a` is in lexicographic order
475 !> wrt `b`, `.false.` otherwise
476 !<--------------------------------------------------------------
477 function lexicographic_order(n, a, b) result(a_before_b)
478 implicit none
479 integer, intent(in) :: n
480 integer, intent(in) :: a(n)
481 integer, intent(in) :: b(n)
482 logical :: a_before_b
483 !local
484 integer :: i
485
486 a_before_b = .true.
487 do i = 1, n
488 if (a(i) .gt. b(i)) then
489 a_before_b = .false.
490 exit
491 else if (a(i) .lt. b(i)) then
492 a_before_b = .true.
493 exit
494 end if
495 end do
496
497 end function lexicographic_order
498
499 !>---------------------------------------------------------------
500 !> @brief global_heapsort
501 !<--------------------------------------------------------------
502 subroutine global_heapsort(n, indx, i, j, isgn)
503 !
504 ! SORT_HEAP_EXTERNAL externally sorts a list
505 ! of items into ascending order.
506 !
507 ! Discussion:
508 !
509 ! The actual list of data is not passed to the routine.
510 ! Hence this routine may be used to sort integers, reals,
511 ! numbers, names, dates, shoe sizes, and so on.
512 ! After each call, the routine asks
513 ! the user to compare or interchange two items, until a special
514 ! return value signals that the sorting is completed.
515 !
516 ! Licensing:
517 !
518 ! This code is distributed under the GNU LGPL license.
519 !
520 ! Modified:
521 !
522 ! 05 February 2004
523 !
524 ! Author:
525 !
526 ! Original FORTRAN77 version by Albert Nijenhuis, Herbert Wilf.
527 ! FORTRAN90 version by John Burkardt.
528 !
529 ! Reference:
530 !
531 ! Albert Nijenhuis and Herbert Wilf,
532 ! Combinatorial Algorithms,
533 ! Academic Press, 1978, second edition,
534 ! ISBN 0-12-519260-6.
535 !
536 ! Parameters:
537 !
538 ! Input, integer ( kind = 4 ) N,
539 ! the number of items to be sorted.
540 !
541 ! Input/output, integer ( kind = 4 ) INDX,
542 ! the main communication signal.
543 !
544 ! The user must set INDX to 0 before the first call.
545 ! Thereafter, the user should not change the value of INDX until
546 ! the sorting is done.
547 !
548 ! On return, if INDX is
549 !
550 ! greater than 0,
551 ! * interchange items I and J;
552 ! * call again.
553 !
554 ! less than 0,
555 ! * compare items I and J;
556 ! * set ISGN = -1 if I < J, ISGN = +1 if J < I;
557 ! * call again.
558 !
559 ! equal to 0, the sorting is done.
560 !
561 ! Example of use : sort array of thing of legnth nnz
562 ! Code
563 !
564 ! if (nnz.lt.2) return
565 ! Initialize.
566 ! i = 0
567 ! indx = 0
568 ! isgn = 0
569 ! j = 0
570 ! do
571 ! call global_heapsort(nnz, indx, i,j,isgn)
572 ! if (indx .gt. 0 ) then
573 ! ! SWAP ELEMENT
574 ! array(i) and array(j)
575 ! else if ( indx .lt. 0) then
576 ! ! COMPARE (array(i) and array(j) )
577 ! isgn = 0
578 ! if ( array(i) .lt. array(j) ) isgn = -1
579 ! if ( array(i) .gt. array(j) ) isgn = 1
580 ! else if ( indx .eq. 0 ) then
581 ! exit
582 ! end if
583 ! end do
584 !
585 !
586 !
587 ! Output, integer ( kind = 4 ) I, J, the indices of two items.
588 ! On return with INDX positive, elements I and J should
589 ! be interchanged.
590 ! On return with INDX negative, elements I and J should
591 ! be compared, and
592 ! the result reported in ISGN on the next call.
593 !
594 ! Input, integer ( kind = 4 ) ISGN, results of comparison of elements
595 ! I and J. (Used only when the previous call returned INDX less than 0).
596 ! ISGN <= 0 means I is less than or equal to J;
597 ! 0 <= ISGN means I is greater than or equal to J.
598 !
599 implicit none
600
601 integer(kind=4) i
602 integer(kind=4), save :: i_save = 0
603 integer(kind=4) indx
604 integer(kind=4) isgn
605 integer(kind=4) j
606 integer(kind=4), save :: j_save = 0
607 integer(kind=4), save :: k = 0
608 integer(kind=4), save :: k1 = 0
609 integer(kind=4) n
610 integer(kind=4), save :: n1 = 0
611 !
612 ! INDX = 0: This is the first call.
613 !
614 if (indx == 0) then
615
616 i_save = 0
617 j_save = 0
618 k = n/2
619 k1 = k
620 n1 = n
621 !
622 ! INDX < 0: The user is returning the results of a comparison.
623 !
624 else if (indx < 0) then
625
626 if (indx == -2) then
627
628 if (isgn < 0) then
629 i_save = i_save + 1
630 end if
631
632 j_save = k1
633 k1 = i_save
634 indx = -1
635 i = i_save
636 j = j_save
637 return
638
639 end if
640
641 if (0 < isgn) then
642 indx = 2
643 i = i_save
644 j = j_save
645 return
646 end if
647
648 if (k <= 1) then
649
650 if (n1 == 1) then
651 i_save = 0
652 j_save = 0
653 indx = 0
654 else
655 i_save = n1
656 n1 = n1 - 1
657 j_save = 1
658 indx = 1
659 end if
660
661 i = i_save
662 j = j_save
663 return
664
665 end if
666
667 k = k - 1
668 k1 = k
669 !
670 ! 0 < INDX, the user was asked to make an interchange.
671 !
672 else if (indx == 1) then
673
674 k1 = k
675
676 end if
677
678 do
679
680 i_save = 2*k1
681
682 if (i_save == n1) then
683 j_save = k1
684 k1 = i_save
685 indx = -1
686 i = i_save
687 j = j_save
688 return
689 else if (i_save <= n1) then
690 j_save = i_save + 1
691 indx = -2
692 i = i_save
693 j = j_save
694 return
695 end if
696
697 if (k <= 1) then
698 exit
699 end if
700
701 k = k - 1
702 k1 = k
703
704 end do
705
706 if (n1 == 1) then
707 i_save = 0
708 j_save = 0
709 indx = 0
710 i = i_save
711 j = j_save
712 else
713 i_save = n1
714 n1 = n1 - 1
715 j_save = 1
716 indx = 1
717 i = i_save
718 j = j_save
719 end if
720
721 return
722
723 end subroutine global_heapsort
724
725 !>---------------------------------------------------------------
726 !> @brief ifind
727 !<--------------------------------------------------------------
728 function ifind(narray, array, tobefound) result(i)
729 implicit none
730 integer, intent(in) :: narray
731 integer, intent(in) :: tobefound
732 integer, intent(in) :: array(narray)
733 integer :: i
734 !local
735 logical :: found
736
737 i = 1
738 found = (array(i) .eq. tobefound)
739 do while ((.not. found) .and. (i .lt. narray))
740 i = i + 1
741 found = (array(i) .eq. tobefound)
742 end do
743 if (.not. found) i = 0
744
745 end function ifind
746
747 !>---------------------------------------------------------------
748 !> @brief double_col_permute
749 !<--------------------------------------------------------------
750 subroutine double_col_permute(m, n, p, a)
751 !****************************************************************************
752 !
753 ! ! R8COL_PERMUTE permutes an R8COL in place.
754 !
755 ! Discussion:
756 !
757 ! An R8COL is an M by N array of double precision values, regarded
758 ! as an array of N columns of length M.
759 !
760 ! The same logic can be used to permute an array of objects of any
761 ! arithmetic type, or an array of objects of any complexity. The only
762 ! temporary storage required is enough to store a single object. The number
763 ! of data movements made is N + the number of cycles of order 2 or more,
764 ! which is never more than N + N/2.
765 !
766 ! Example:
767 !
768 ! Input:
769 !
770 ! M = 2
771 ! N = 5
772 ! P = ( 2, 4, 5, 1, 3 )
773 ! A = ( 1.0, 2.0, 3.0, 4.0, 5.0 )
774 ! (11.0, 22.0, 33.0, 44.0, 55.0 )
775 !
776 ! Output:
777 !
778 ! A = ( 2.0, 4.0, 5.0, 1.0, 3.0 )
779 ! ( 22.0, 44.0, 55.0, 11.0, 33.0 ).
780 !
781 ! Licensing:
782 !
783 ! This code is distributed under the GNU LGPL license.
784 !
785 ! Modified:
786 !
787 ! 04 December 2017 (Enrico Facca)
788 ! simple modification and adaptation to my code
789 !
790 ! Author:
791 !
792 ! John Burkardt
793 !
794 ! Parameters:
795 !
796 ! Input, integer ( kind = 4 ) M, the dimension of objects.
797 !
798 ! Input, integer ( kind = 4 ) N, the number of objects.
799 !
800 ! Input, integer ( kind = 4 ) P(N), the permutation. P(I) = J means
801 ! that the I-th element of the output array should be the J-th
802 ! element of the input array. P must be a legal permutation
803 ! of the integers from 1 to N, otherwise the algorithm will
804 ! fail catastrophically.
805 !
806 ! Input/output, real ( kind = 8 ) A(M,N), the array to be permuted.
807 !
808 implicit none
809
810 integer(kind=4) m
811 integer(kind=4) n
812
813 real(kind=double) a(m, n)
814 real(kind=double), allocatable :: a_temp(:)
815
816 integer(kind=4) res
817 integer(kind=4) iget
818 integer(kind=4) iput
819 integer(kind=4) istart
820 integer(kind=4) p(n)
821 !
822 ! Search for the next element of the permutation that has not been used.
823 !
824 allocate (a_temp(m), stat=res)
825 if (res .ne. 0) write (*, *) ' Error allocation double double_col_permute'
826
827 do istart = 1, n
828
829 if (p(istart) < 0) then
830
831 cycle
832
833 else if (p(istart) == istart) then
834
835 p(istart) = -p(istart)
836 cycle
837
838 else
839
840 a_temp(1:m) = a(1:m, istart)
841 iget = istart
842 !
843 ! Copy the new value into the vacated entry.
844 !
845 do
846
847 iput = iget
848 iget = p(iget)
849
850 p(iput) = -p(iput)
851
852 if (iget < 1 .or. n < iget) then
853 write (*, '(a)') ' '
854 write (*, '(a)') 'R8COL_PERMUTE - Fatal error!'
855 write (*, '(a)') ' A permutation index is out of range.'
856 write (*, '(a,i8,a,i8)') ' P(', iput, ') = ', iget
857 stop
858 end if
859
860 if (iget == istart) then
861 a(1:m, iput) = a_temp(1:m)
862 exit
863 end if
864
865 a(1:m, iput) = a(1:m, iget)
866
867 end do
868
869 end if
870
871 end do
872 !
873 ! Restore the signs of the entries.
874 !
875 p(1:n) = -p(1:n)
876
877 return
878
879 deallocate (a_temp, stat=res)
880 if (res .ne. 0) write (*, *) ' Error deallocation double double_col_permute'
881
882 end subroutine double_col_permute
883
884 !>---------------------------------------------------------------
885 !> @brief integer_col_permute
886 !<--------------------------------------------------------------
887 subroutine integer_col_permute(m, n, p, a)
888
889 !**************************************************************************
890 !
891 ! ! R8COL_PERMUTE permutes an R8COL in place.
892 !
893 ! Discussion:
894 !
895 ! An R8COL is an M by N array of double precision values, regarded
896 ! as an array of N columns of length M.
897 !
898 ! The same logic can be used to permute an array of objects of any
899 ! arithmetic type, or an array of objects of any complexity. The only
900 ! temporary storage required is enough to store a single object. The number
901 ! of data movements made is N + the number of cycles of order 2 or more,
902 ! which is never more than N + N/2.
903 !
904 ! Example:
905 !
906 ! Input:
907 !
908 ! M = 2
909 ! N = 5
910 ! P = ( 2, 4, 5, 1, 3 )
911 ! A = ( 1.0, 2.0, 3.0, 4.0, 5.0 )
912 ! (11.0, 22.0, 33.0, 44.0, 55.0 )
913 !
914 ! Output:
915 !
916 ! A = ( 2.0, 4.0, 5.0, 1.0, 3.0 )
917 ! ( 22.0, 44.0, 55.0, 11.0, 33.0 ).
918 !
919 ! Licensing:
920 !
921 ! This code is distributed under the GNU LGPL license.
922 !
923 ! Modified:
924 !
925 ! 04 December 2017 (Enrico Facca)
926 ! simple modification and adaptation to my code
927 !
928 ! Author:
929 !
930 ! John Burkardt
931 !
932 ! Parameters:
933 !
934 ! Input, integer ( kind = 4 ) M, the dimension of objects.
935 !
936 ! Input, integer ( kind = 4 ) N, the number of objects.
937 !
938 ! Input, integer ( kind = 4 ) P(N), the permutation. P(I) = J means
939 ! that the I-th element of the output array should be the J-th
940 ! element of the input array. P must be a legal permutation
941 ! of the integers from 1 to N, otherwise the algorithm will
942 ! fail catastrophically.
943 !
944 ! Input/output, real ( kind = 8 ) A(M,N), the array to be permuted.
945 !
946 implicit none
947
948 integer(kind=4) m
949 integer(kind=4) n
950
951 integer(kind=4) :: a(m, n)
952 integer(kind=4), allocatable :: a_temp(:)
953
954 integer(kind=4) res
955 integer(kind=4) iget
956 integer(kind=4) iput
957 integer(kind=4) istart
958 integer(kind=4) p(n)
959 !
960 ! Search for the next element of the permutation that has not been used.
961 !
962 allocate (a_temp(m), stat=res)
963 if (res .ne. 0) write (*, *) ' Error allocation double double_col_permute'
964
965 do istart = 1, n
966
967 if (p(istart) < 0) then
968
969 cycle
970
971 else if (p(istart) == istart) then
972
973 p(istart) = -p(istart)
974 cycle
975
976 else
977
978 a_temp(1:m) = a(1:m, istart)
979 iget = istart
980 !
981 ! Copy the new value into the vacated entry.
982 !
983 do
984
985 iput = iget
986 iget = p(iget)
987
988 p(iput) = -p(iput)
989
990 if (iget < 1 .or. n < iget) then
991 write (*, '(a)') ' '
992 write (*, '(a)') 'integer COL_PERMUTE - Fatal error!'
993 write (*, '(a)') ' A permutation index is out of range.'
994 write (*, '(a,i8,a,i8)') ' P(', iput, ') = ', iget
995 stop
996 end if
997
998 if (iget == istart) then
999 a(1:m, iput) = a_temp(1:m)
1000 exit
1001 end if
1002
1003 a(1:m, iput) = a(1:m, iget)
1004
1005 end do
1006
1007 end if
1008
1009 end do
1010 !
1011 ! Restore the signs of the entries.
1012 !
1013 p(1:n) = -p(1:n)
1014
1015 return
1016
1017 deallocate (a_temp, stat=res)
1018 if (res .ne. 0) write (*, *) &
1019 ' Error deallocation double double_col_permute'
1020
1021 end subroutine integer_col_permute
1022
1023 !>------------------------------------------------------------------
1024 !> @brief Evaluates the weighted p-norm
1025 !>
1026 !> @param[in] ndata: length of input array
1027 !> @param[in] power: power for p-norm (`0` for infinity norm)
1028 !> @param[in] data: input array of dimension `ndata`
1029 !> @param[in] weight: array of weights (optional)
1030 !> @result real(double), (weighted) p-norm of `data`
1031 !<------------------------------------------------------------------
1032 function p_norm(ndata, power, data, weight) result(total)
1033 implicit none
1034 integer, intent(in) :: ndata
1035 real(kind=double), intent(in) :: power
1036 real(kind=double), intent(in) :: data(ndata)
1037 real(kind=double), intent(in), optional :: weight(ndata)
1038 real(kind=double) :: total
1039 !local
1040 integer :: i
1041 real(kind=double) :: ddot
1042
1043 if (abs(power) < small) then
1044 total = maxval(abs(data))
1045 else
1046 if (present(weight)) then
1047 if (abs(power - one) < small) then
1048 total = ddot(ndata, abs(data), 1, weight, 1)
1049 else
1050 total = zero
1051 do i = 1, ndata
1052 total = total + abs(data(i))**power*weight(i)
1053 end do
1054 total = total**(one/power)
1055 end if
1056 else
1057 if (abs(power - one) < small) then
1058 total = sum(abs(data))
1059 else
1060 total = zero
1061 do i = 1, ndata
1062 total = total + abs(data(i))**power
1063 end do
1064 total = total**(one/power)
1065 end if
1066 end if
1067 end if
1068
1069 end function p_norm
1070
1071 !>-----------------------------------------------------
1072 !> @brief Procedure orthogonalizing a vector w.r.t. a
1073 !> a set of vectors
1074 !>
1075 !> @param[in ] dim: vectors dimension
1076 !> @param[in ] nvectors: number of vectors
1077 !> @param[in ] vectors: set of vectors wrt `x` is orthogonalized
1078 !> @param[inout] x: vector to be orthogonalized
1079 !<-----------------------------------------------------s
1080 subroutine ortogonalize(dim, nvectors, vectors, x)
1081 implicit none
1082 integer, intent(in) :: dim
1083 integer, intent(in) :: nvectors
1084 real(kind=double), intent(in) :: vectors(dim, nvectors)
1085 real(kind=double), intent(inout) :: x(dim)
1086 ! local
1087 integer :: i
1088 real(kind=double) :: ddot, alpha, beta
1089
1090 do i = 1, nvectors
1091 beta = ddot(dim, vectors(1, i), 1, x, 1)
1092 alpha = -beta/ddot(dim, vectors(1, i), 1, vectors(1, i), 1)
1093 !x=x-alpha*vectors(:,i)
1094 call daxpy(dim, alpha, vectors(1, i), 1, x, 1)
1095 end do
1096
1097 end subroutine ortogonalize
1098
1099 !>-------------------------------------------------------------
1100 !> @brief Procedure that computes the projection of a vector
1101 !> onto the plane orthogonal to another vector (`normal`)
1102 !>
1103 !> @param[in ] ndim: dimension of the vectors
1104 !> @param[in ] vector: vector to be projected (dimension `ndim`)
1105 !> @param[in ] normal: normal to the plane (dimension `ndim`)
1106 !> @param[out] result: projected vector (dimension `ndim`)
1107 !<-------------------------------------------------------------
1108 subroutine orthogonal_projection(ndim, vector, normal, res_proj)
1109 implicit none
1110 integer, intent(in) :: ndim
1111 real(kind=double), intent(in) :: vector(ndim)
1112 real(kind=double), intent(in) :: normal(ndim)
1113 real(kind=double), intent(out) :: res_proj(ndim)
1114 ! local vars
1115 real(kind=double) :: alpha, beta
1116 real(kind=double) :: ddot
1117
1118 beta = ddot(ndim, vector, 1, normal, 1)
1119 alpha = -beta/ddot(ndim, normal, 1, normal, 1)
1120 !x=x-alpha*vectors(:,i)
1121 call dcopy(ndim, vector, 1, res_proj, 1)
1122 call daxpy(ndim, alpha, normal, 1, res_proj, 1)
1123
1124 end subroutine orthogonal_projection
1125
1126 !>-------------------------------------------------------------
1127 !> @brief Info procedure for `globals::file`
1128 !> @details Print the name of the file and the associated
1129 !> unit number
1130 !>
1131 !> @param[in] lun: unit number for output message
1132 !<-------------------------------------------------------------
1133 subroutine fn_print(this, lun)
1134 implicit none
1135 class(file), intent(in) :: this
1136 integer, intent(in) :: lun
1137
1138 write (lun, '(a,a,a,i3)') ' filename ', etb(this%fn), &
1139 ' linked to lun ', this%lun
1140
1141 end subroutine fn_print
1142
1143 !>-------------------------------------------------------------
1144 !> Get directory name
1145 !>
1146 !> @param[in] lun: unit number for output message
1147 !> @return (char) directory name
1148 !<-------------------------------------------------------------
1149 function get_dirname(str_file) result(str_dir)
1150 implicit none
1151 character(len=*), intent(in) :: str_file
1152 character(len=len_trim(adjustl(str_file))) :: str_dir
1153 !local
1154 integer :: nstr, pbar
1155
1156 str_dir(:) = ' '
1157
1158 nstr = len(etb(str_file))
1159 pbar = scan(etb(str_file), "/", back=.true.)
1160 if (pbar .eq. 0) then
1161 str_dir(1:1) = '.'
1162 else
1163 str_dir(1:pbar) = str_file(1:pbar)
1164 end if
1165
1166 end function get_dirname
1167
1168 !>-------------------------------------------------------------
1169 !> @brief Static constructor for `globals::file`
1170 !>
1171 !> @param[in] lun_err: unit number for error messages
1172 !> @param[in] fn: name of the file
1173 !> @param[in] lun: unit number to associate to the file
1174 !> @param[in] io_flag: `"in"` if filename is an input
1175 !> file and its existence must be checked, `"out"` if
1176 !> it is an output file
1177 !> @param[in] mandatory_input: (optional)
1178 !> specify if input file is mandatory:
1179 !> `.true.`: file is mandatory, stop if file does
1180 !> not exists (default value)
1181 !> `.false.`: file is optional, proceed if file does
1182 !> not exists
1183 !> @param[in] folder: (optional) specify if input file is
1184 !> a file or a folder:
1185 !> * `.true.`: input path is folder (check existence and not open unit)
1186 !> * `.false.`: input path is file (default value,
1187 !> check existence and open if `mandatory_input = .true.`)
1188 !> @param[in] verbose: (optional) logical flag for additional messages
1189 !> @param[inout] info: (optional) flag for existence of file:
1190 !> returns `-1` if file does not exist
1191 !<-------------------------------------------------------------
1192 subroutine fn_init(this, lun_err, fn, lun, io_flag, &
1193 mandatory_input, folder, verbose, info)
1194 implicit none
1195 class(file), intent(inout) :: this
1196 integer, intent(in) :: lun_err
1197 character(len=*), intent(in) :: fn
1198 integer, intent(in) :: lun
1199 character(len=*), intent(in) :: io_flag
1200 logical, intent(in), optional :: mandatory_input
1201 logical, intent(in), optional :: folder
1202 logical, intent(in), optional :: verbose
1203 integer, intent(inout), optional :: info
1204 ! local vars
1205 logical :: exist, file_exist, rc, mandatory, open_unit, printmsg
1206 integer :: res
1207
1208 this%fn = etb(fn)
1209 this%lun = lun
1210
1211 mandatory = .true.
1212 if (present(mandatory_input)) mandatory = mandatory_input
1213
1214 printmsg = .true.
1215 if (present(verbose)) printmsg = verbose
1216
1217 if (present(info)) info = 0
1218
1219 ! handle folders
1220 open_unit = .true.
1221 if (present(folder)) open_unit = .not. folder
1222
1223 ! for input files or folders check existence
1224 ! if marked as not mandatory print a warning message
1225 ! otherwise it stops
1226 if (io_flag .eq. 'in') then
1227 inquire (file=this%fn, exist=exist)
1228 this%exist = exist
1229 if (.not. exist) then
1230 ! warning or stop
1231 if (mandatory) then
1232 file_exist = ioerr(lun_err, err_io, 'file%init', &
1233 ' mandatory named :'//etb(this%fn)//' not found', lun)
1234 else
1235 if (printmsg) &
1236 file_exist = ioerr(lun_err, wrn_io, 'file%init', &
1237 ' optional named : '//etb(this%fn)//' not found', lun)
1238 end if
1239 if (present(info)) info = -1
1240 ! exit
1241 return
1242 end if
1243 end if
1244
1245 ! if exist and it is not a folder open unit
1246 if (open_unit) then
1247 open (lun, file=this%fn, iostat=res)
1248 if (res .ne. 0) rc = ioerr(lun_err, err_io, &
1249 'file%init', &
1250 'err opening file '//etb(this%fn), lun)
1251 this%exist = .true.
1252 end if
1253
1254 end subroutine fn_init
1255
1256 !>-------------------------------------------------------------
1257 !> @brief Static destructor for `globals::file`
1258 !>
1259 !> @param[in] lun_err: unit number for output error message
1260 !<-------------------------------------------------------------
1261 subroutine fn_kill(this, lun_err)
1262 implicit none
1263 class(file), intent(inout) :: this
1264 integer, intent(in) :: lun_err
1265 ! local vars
1266 logical :: rc, is_open
1267 integer :: res
1268
1269 inquire (this%lun, opened=is_open)
1270 if (is_open) then
1271 close (this%lun, iostat=res)
1272 if (res .ne. 0) rc = ioerr(lun_err, err_io, &
1273 'file%kill', &
1274 'err closing file '//etb(this%fn), res)
1275 this%exist = .false.
1276 end if
1277 this%fn = ' '
1278 this%lun = -1
1279
1280 end subroutine fn_kill
1281
1282end module globals
character(len=256) function errmsg(errno, addmsg, addint)
Return message depending on input number.
real(kind=double) function, dimension(3) cross(veca, vecb)
Function that calculates cross-products.
subroutine integer_col_permute(m, n, p, a)
integer_col_permute
real(kind=double) function, dimension(3) avg_vec3(avg_type, veca, vecb, vecc)
Function that calculates vectors averages.
integer, parameter err_val
Error in parameter value.
integer, parameter err_alloc
Error allocation failed.
integer, parameter err_vtk
Error VTK library.
subroutine global_heapsort(n, indx, i, j, isgn)
global_heapsort
subroutine fn_init(this, lun_err, fn, lun, io_flag, mandatory_input, folder, verbose, info)
Static constructor for globals::file.
subroutine fn_kill(this, lun_err)
Static destructor for globals::file.
character(len=len_trim(adjustl(strin))) function erase_comment(strin)
Erase comments from a string.
subroutine fn_print(this, lun)
Info procedure for globals::file.
real(kind=double) function avg_scal(avg_type, a, b, c)
Function that calculates scalar averages.
integer, parameter err_write
Error writing file.
integer, parameter wrn_io
File or directory does not exist.
character(len=len_trim(adjustl(strin))) function etb(strin)
Return string strin with no preceding and trailing spaces.
character(len=len(strin)) function to_upper(strin)
Transform string to upper case.
logical function lexicographic_order(n, a, b)
Check if the first array is in lexicographic order with respect to the second.
integer, parameter wrn_inp
Error in input parameter.
subroutine double_col_permute(m, n, p, a)
double_col_permute
integer, parameter err_inp
Error in input parameter.
real(kind=double) function p_norm(ndata, power, data, weight)
Evaluates the weighted p-norm.
subroutine orthogonal_projection(ndim, vector, normal, res_proj)
Procedure that computes the projection of a vector onto the plane orthogonal to another vector (norma...
integer, parameter wrn_out
Error in outour parameter.
integer, parameter err_dealloc
Error deallocation failed.
subroutine ortogonalize(dim, nvectors, vectors, x)
Procedure orthogonalizing a vector w.r.t. a a set of vectors.
integer, parameter wrn_write
Error writing file.
integer, parameter err_out
Error in outour parameter.
character(len=len(strin)) function to_lower(strin)
Transform string to lowercase case.
logical function ioerr(lun, errno, call_proc, add_msg, add_int)
Handle and write alert I/O warnings and errors.
integer function ifind(narray, array, tobefound)
ifind
subroutine unique_of_sorted(n_elements, elements, nunique)
Given a sorted array, it is returned with the list of uniques elements in the first positions.
character(len=len_trim(adjustl(str_file))) function get_dirname(str_file)
integer, parameter err_read
Error reading file.
integer, parameter wrn_read
Error reading file.
subroutine isort(narray, array)
Simple sort algorithm to sort in increasing order an integer array. To be used only for small array....
integer, parameter wrn_val
Error in input/outour parameter.
integer, parameter err_io
File or directory does not exist.
This module contains global variables and utility functions. Detailed description of the module.
real(kind=double), parameter onehalf
real(kind=double), parameter onethird
real(kind=double), parameter small
real(kind=double), parameter zero
integer, parameter double
Double precision parameter for real variables.
real(kind=double), parameter one