V3FIT
v3_utilities.f
1 ! JDH 08-12-2004. First version. Some subroutines modeled after Numerical Recipes
2 ! nrutil subroutines
3 ! SPH 10-31-2017. Added MPI_ABORT
4 
5 !*******************************************************************************
6 ! File v3_utilitlies.f
7 ! Contains module v3_utilitlies
8 ! Utility Functions for V3FIT
9 
10 !*******************************************************************************
11 ! MODULE v3_utilitlies
12 ! (Utilities, for the V3FIT code)
13 ! SECTION I. Variable Declarations
14 ! SECTION II. Interface Blocks
15 ! SECTION III. Error Trapping
16 ! SECTION IV. Input-Output Utilities
17 !*******************************************************************************
18 
19  MODULE v3_utilities
20  USE mpi_inc
21  IMPLICIT NONE
22 
23 !*******************************************************************************
24 ! SECTION I. Variable Declarations
25 !*******************************************************************************
26 
27 !-------------------------------------------------------------------------------
28 ! Type declarations - lengths of reals, integers, and complexes.
29 ! Frequently used mathematical constants, lots of extra precision.
30 ! Make type declarations and constants Private, so there are no conflicts.
31 !-------------------------------------------------------------------------------
32  INTEGER, PARAMETER :: rprec = selected_real_kind(12,100)
33  INTEGER, PARAMETER :: iprec = selected_int_kind(8)
34  INTEGER, PARAMETER :: cprec = kind((1.0_rprec,1.0_rprec))
35  REAL(rprec), PARAMETER :: pi=3.14159265358979323846264338328_rprec
36  REAL(rprec), PARAMETER :: twopi=6.28318530717958647692528677_rprec
37  REAL(rprec), PARAMETER :: one = 1.0_rprec
38  REAL(rprec), PARAMETER :: zero = 0.0_rprec
39  INTEGER :: mpi_err, myrank=0
40 
41 ! USE stell_kinds, only : rprec, iprec, cprec
42 ! USE stell_constants, only: pi, twopi, one, zero
43  PRIVATE rprec, iprec, cprec, pi, twopi, one, zero, mpi_err
44 
45 !-------------------------------------------------------------------------------
46 ! JDH 08-13-04. Perhaps add variable for error IO unit numnber, and print there also
47 !-------------------------------------------------------------------------------
48 
49 !*******************************************************************************
50 ! SECTION II. INTERFACE BLOCKS
51 !*******************************************************************************
52 !-------------------------------------------------------------------------------
53 ! assert, with varying numbers of arguments
54 !-------------------------------------------------------------------------------
55  INTERFACE assert
56  MODULE PROCEDURE assert1,assert2,assert3,assert4,assert_v
57  END INTERFACE
58 
59 !-------------------------------------------------------------------------------
60 ! assert_eq, with varying numbers of arguments
61 !-------------------------------------------------------------------------------
62  INTERFACE assert_eq
63  MODULE PROCEDURE assert_eq2,assert_eq3,assert_eq4,assert_eqn
64  END INTERFACE
65 
66  CONTAINS
67 
68 !*******************************************************************************
69 ! SECTION III. Error Trapping
70 !*******************************************************************************
71 
72 !-------------------------------------------------------------------------------
73 ! Assert
74 ! This subroutine is modeled after 'assert' in the Numerical Recipes in F90.
75 ! The last argument is a string, the first argument(s) are logicals
76 ! If any of the logicals are false, an error message is printed, and the
77 ! subroutine either stops or continues.
78 ! The optional argument err_class determines if the error is fatal, or just
79 ! a warning. The default action is fatal (execution stops). If the argument
80 ! err_class is present, and its first character is 'w' or 'W', then execution
81 ! continues.
82 ! Different versions have 1, 2, 3, 4, or a vector of logicals.
83 ! Assert, 1 logical
84 !-------------------------------------------------------------------------------
85  SUBROUTINE assert1(n1,string,err_class)
86 ! Argument Declaration
87  CHARACTER(LEN=*), INTENT(IN) :: string
88  LOGICAL, INTENT(IN) :: n1
89  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
90 
91 ! Local variable declarations
92  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
93  CHARACTER(LEN=1) :: first_char
94  LOGICAL :: lfatal
95 #if defined(MPI_OPT)
96  CALL mpi_comm_rank(mpi_comm_world, myrank, mpi_err)
97 #endif
98 ! Start of executable code
99  IF (.not.n1) THEN
100 ! IF (myrank .eq. 0) THEN
101  WRITE (*,fmt) 'error: an assertion failed with this tag:', &
102  & string
103  WRITE(*,*) ' n1 = ',n1
104 ! END IF
105 ! Is error Fatal or Warning?
106  lfatal = .true.
107  IF (PRESENT(err_class)) THEN
108  first_char = err_class(1:1)
109  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
110  & lfatal = .false.
111  ENDIF
112  IF (lfatal) THEN
113 #if defined(MPI_OPT)
114  CALL mpi_abort(mpi_comm_world, 1, mpi_err)
115 #else
116  stop 'program terminated by assert1'
117 #endif
118  ELSE
119  IF (myrank.eq.0) &
120  & WRITE(*,*) ' end of warning error message from assert1'
121  END IF
122  END IF
123  END SUBROUTINE assert1
124 
125 !-------------------------------------------------------------------------------
126 ! Assert, 2 logicals
127 !-------------------------------------------------------------------------------
128  SUBROUTINE assert2(n1,n2,string,err_class)
129 ! Argument Declaration
130  CHARACTER(LEN=*), INTENT(IN) :: string
131  LOGICAL, INTENT(IN) :: n1, n2
132  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
133 
134 ! Local variable declarations
135  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
136  CHARACTER(LEN=1) :: first_char
137  LOGICAL :: lfatal
138 #if defined(MPI_OPT)
139  CALL mpi_comm_rank(mpi_comm_world, myrank, mpi_err)
140 #endif
141 
142 ! Start of executable code
143  IF (.not.(n1 .and. n2)) THEN
144  IF (myrank .eq. 0) THEN
145  WRITE (*,fmt) 'error: an assertion failed with this tag:', &
146  & string
147  WRITE(*,*) ' n1, n2 = ',n1, n2
148  END IF
149 ! Is error Fatal or Warning?
150  lfatal = .true.
151  IF (PRESENT(err_class)) THEN
152  first_char = err_class(1:1)
153  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
154  & lfatal = .false.
155  ENDIF
156  IF (lfatal) THEN
157 #if defined(MPI_OPT)
158  CALL mpi_abort(mpi_comm_world, 1, mpi_err)
159 #else
160  stop 'program terminated by assert2'
161 #endif
162  ELSE
163  IF (myrank .eq. 0) &
164  & WRITE(*,*) ' end of warning error message from assert2'
165  END IF
166  END IF
167  END SUBROUTINE assert2
168 
169 !-------------------------------------------------------------------------------
170 ! Assert, 3 logicals
171 !-------------------------------------------------------------------------------
172  SUBROUTINE assert3(n1,n2,n3,string,err_class)
173 ! Argument Declaration
174  CHARACTER(LEN=*), INTENT(IN) :: string
175  LOGICAL, INTENT(IN) :: n1,n2,n3
176  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
177 
178 ! Local variable declarations
179  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
180  CHARACTER(LEN=1) :: first_char
181  LOGICAL :: lfatal
182 #if defined(MPI_OPT)
183  CALL mpi_comm_rank(mpi_comm_world, myrank, mpi_err)
184 #endif
185 
186 ! Start of executable code
187  IF (.not.(n1 .and. n2 .and. n3)) THEN
188  IF (myrank .eq. 0) THEN
189  WRITE (*,fmt) 'error: an assertion failed with this tag:', &
190  & string
191  WRITE(*,*) ' n1, n2, n3 = ',n1, n2, n3
192  END IF
193 ! Is error Fatal or Warning?
194  lfatal = .true.
195  IF (PRESENT(err_class)) THEN
196  first_char = err_class(1:1)
197  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
198  & lfatal = .false.
199  ENDIF
200  IF (lfatal) THEN
201 #if defined(MPI_OPT)
202  CALL mpi_abort(mpi_comm_world, 1, mpi_err)
203 #else
204  stop 'program terminated by assert3'
205 #endif
206  ELSE
207  IF (myrank .eq. 0) &
208  & WRITE(*,*) ' end of warning error message from assert3'
209  END IF
210  END IF
211  END SUBROUTINE assert3
212 
213 !-------------------------------------------------------------------------------
214 ! Assert, 4 logicals
215 !-------------------------------------------------------------------------------
216  SUBROUTINE assert4(n1,n2,n3,n4,string,err_class)
217 ! Argument Declaration
218  CHARACTER(LEN=*), INTENT(IN) :: string
219  LOGICAL, INTENT(IN) :: n1,n2,n3,n4
220  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
221 
222 ! Local variable declarations
223  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
224  CHARACTER(LEN=1) :: first_char
225  LOGICAL :: lfatal
226 #if defined(MPI_OPT)
227  CALL mpi_comm_rank(mpi_comm_world, myrank, mpi_err)
228 #endif
229 
230 ! Start of executable code
231  IF (.not. (n1 .and. n2 .and. n3 .and. n4)) THEN
232  IF (myrank .eq. 0) THEN
233  WRITE (*,fmt) 'error: an assertion failed with this tag:', &
234  & string
235  WRITE(*,*) ' n1, n2, n3, n4 = ',n1, n2, n3, n4
236  END IF
237 ! Is error Fatal or Warning?
238  lfatal = .true.
239  IF (PRESENT(err_class)) THEN
240  first_char = err_class(1:1)
241  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
242  & lfatal = .false.
243  ENDIF
244  IF (lfatal) THEN
245 #if defined(MPI_OPT)
246  CALL mpi_abort(mpi_comm_world, 1, mpi_err)
247 #else
248  stop 'program terminated by assert4'
249 #endif
250  ELSE
251  IF (myrank .eq. 0) &
252  & WRITE(*,*) ' end of warning error message from assert4'
253  END IF
254  END IF
255  END SUBROUTINE assert4
256 
257 !-------------------------------------------------------------------------------
258 ! Assert, vector of logicals
259 !-------------------------------------------------------------------------------
260  SUBROUTINE assert_v(n,string,err_class)
261 ! Argument Declaration
262  CHARACTER(LEN=*), INTENT(IN) :: string
263  LOGICAL, DIMENSION(:), INTENT(IN) :: n
264  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
265 
266 ! Local variable declarations
267  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
268  INTEGER(iprec) :: ntot, nfalse, ifirst, i
269  CHARACTER(LEN=1) :: first_char
270  LOGICAL :: lfatal
271 #if defined(MPI_OPT)
272  CALL mpi_comm_rank(mpi_comm_world, myrank, mpi_err)
273 #endif
274 
275 ! Start of executable code
276  IF (.not.all(n)) THEN
277  IF (myrank .eq. 0) THEN
278  WRITE (*,fmt) 'error: an assertion failed with this tag:', &
279  & string
280  ntot = SIZE(n)
281  WRITE (*,*) ntot, ' logicals in array. indices of .F. are:'
282  nfalse = 0
283  DO i = 1,ntot
284  IF(.not. n(i)) THEN
285  WRITE(*,*) i
286  nfalse = nfalse + 1
287  END IF
288  END DO
289  WRITE (*,*) nfalse, ' logicals are false'
290  END IF
291 ! Is error Fatal or Warning?
292  lfatal = .true.
293  IF (PRESENT(err_class)) THEN
294  first_char = err_class(1:1)
295  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W')) &
296  & lfatal = .false.
297  ENDIF
298  IF (lfatal) THEN
299 #if defined(MPI_OPT)
300  CALL mpi_abort(mpi_comm_world, 1, mpi_err)
301 #else
302  stop 'program terminated by assert_v'
303 #endif
304  ELSE
305  IF (myrank .eq. 0) &
306  & WRITE(*,*) ' end of warning error message from assert_v'
307  END IF
308  END IF
309  END SUBROUTINE assert_v
310 
311 !-------------------------------------------------------------------------------
312 ! Assert_eq
313 ! This subroutine is modeled after 'assert_eq' in the Numerical Recipes in F90.
314 ! The last argument is a string, the first argument are integers
315 ! If any of the integers is different from the first integer, then
316 ! an error message is printed, and the subroutine either STOPs or continues.
317 ! The optional argument err_class determines if the error is fatal, or just
318 ! a warning. The default action is fatal (execution stops). If the argument
319 ! err_class is present, and its first character is 'w' or 'W', then execution
320 ! continues.
321 ! Different versions have 2, 3, 4, or a vector of integer arguments.
322 ! Note: NR had this as a FUNCTION. I have changed it to a subroutine.
323 ! Assert_eq, 2 integer arguments
324 !-------------------------------------------------------------------------------
325  SUBROUTINE assert_eq2(n1,n2,string,err_class)
326 ! Argument Declaration
327  CHARACTER(LEN=*), INTENT(IN) :: string
328  INTEGER, INTENT(IN) :: n1,n2
329  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
330 
331 ! Local variable declarations
332  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
333  CHARACTER(LEN=1) :: first_char
334  LOGICAL :: lfatal
335 
336 ! Start of executable code
337  IF (.not.(n1 == n2)) THEN
338  WRITE (*,fmt) 'error: an assert_eq failed with this tag:', &
339  & string
340  WRITE (*,*) ' n1, n2 = ',n1, n2
341 ! Is error Fatal or Warning?
342  lfatal = .true.
343  IF (PRESENT(err_class)) THEN
344  first_char = err_class(1:1)
345  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
346  & lfatal = .false.
347  ENDIF
348  IF (lfatal) THEN
349  stop 'program terminated by assert_eq2'
350  ELSE
351  WRITE(*,*) ' end of warning error message from assert_eq2'
352  END IF
353  END IF
354  END SUBROUTINE assert_eq2
355 
356 !-------------------------------------------------------------------------------
357 ! Assert_eq, 3 integer arguments
358 !-------------------------------------------------------------------------------
359  SUBROUTINE assert_eq3(n1,n2,n3,string,err_class)
360 ! Argument Declaration
361  CHARACTER(LEN=*), INTENT(IN) :: string
362  INTEGER, INTENT(IN) :: n1,n2,n3
363  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
364 
365 ! Local variable declarations
366  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
367  CHARACTER(LEN=1) :: first_char
368  LOGICAL :: lfatal
369 
370 ! Start of executable code
371  IF (.not.(n1 == n2 .and. n2 == n3)) THEN
372  WRITE (*,fmt) 'error: an assert_eq failed with this tag:', &
373  & string
374  WRITE (*,*) ' n1, n2, n3 = ',n1, n2, n3
375 ! Is error Fatal or Warning?
376  lfatal = .true.
377  IF (PRESENT(err_class)) THEN
378  first_char = err_class(1:1)
379  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
380  & lfatal = .false.
381  ENDIF
382  IF (lfatal) THEN
383  stop 'program terminated by assert_eq3'
384  ELSE
385  WRITE(*,*) ' end of warning error message from assert_eq3'
386  END IF
387  END IF
388  END SUBROUTINE assert_eq3
389 
390 !-------------------------------------------------------------------------------
391 ! Assert_eq, 4 integer arguments
392 !-------------------------------------------------------------------------------
393  SUBROUTINE assert_eq4(n1,n2,n3,n4,string,err_class)
394 ! Argument Declaration
395  CHARACTER(LEN=*), INTENT(IN) :: string
396  INTEGER, INTENT(IN) :: n1,n2,n3,n4
397  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
398 
399 ! Local variable declarations
400  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
401  CHARACTER(LEN=1) :: first_char
402  LOGICAL :: lfatal
403 
404 ! Start of executable code
405  IF (.not.(n1 == n2 .and. n2 == n3 .and. n3 == n4)) THEN
406  WRITE (*,fmt) 'error: an assert_eq failed with this tag:', &
407  & string
408  WRITE (*,*) ' n1, n2, n3, n4 = ',n1, n2, n3, n4
409 ! Is error Fatal or Warning?
410  lfatal = .true.
411  IF (PRESENT(err_class)) THEN
412  first_char = err_class(1:1)
413  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
414  & lfatal = .false.
415  ENDIF
416  IF (lfatal) THEN
417  stop 'program terminated by assert_eq4'
418  ELSE
419  WRITE(*,*) ' end of warning error message from assert_eq4'
420  END IF
421  END IF
422  END SUBROUTINE assert_eq4
423 
424 !-------------------------------------------------------------------------------
425 ! Assert_eq, a vector of integers
426 !-------------------------------------------------------------------------------
427  SUBROUTINE assert_eqn(nn,string,err_class)
428 ! Argument Declaration
429  CHARACTER(LEN=*), INTENT(IN) :: string
430  INTEGER, DIMENSION(:), INTENT(IN) :: nn
431  INTEGER :: ntot, nne, i
432  CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: err_class
433 
434 ! Local variable declarations
435  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
436  CHARACTER(LEN=1) :: first_char
437  LOGICAL :: lfatal
438 
439 ! Start of executable code
440  IF (.not.(all(nn(2:) == nn(1)))) THEN
441  WRITE (*,fmt) 'error: an assert_eq failed with this tag:', &
442  & string
443  ntot = SIZE(nn)
444  WRITE (*,*) ntot, ' integers in the array.'
445  WRITE (*,*) nn(1), ' is the first value in the array'
446  WRITE(*,*) .ne.' index value (of those to first)'
447  nne = 0
448  DO i = 2,ntot
449  IF (nn(i) .ne. nn(1)) THEN
450  WRITE (*,*) i,nn(i)
451  nne = nne + 1
452  END IF
453  END DO
454  WRITE (*,*) ' There are ',nne, .ne.' integers to first'
455 ! Is error Fatal or Warning?
456  lfatal = .true.
457  IF (PRESENT(err_class)) THEN
458  first_char = err_class(1:1)
459  IF ((first_char .eq. 'w') .or. (first_char .eq. 'W'))
460  & lfatal = .false.
461  ENDIF
462  IF (lfatal) THEN
463  stop 'program terminated by assert_eqn'
464  ELSE
465  WRITE(*,*) ' end of warning error message from assert_eqn'
466  END IF
467  END IF
468  END SUBROUTINE assert_eqn
469 
470 !-------------------------------------------------------------------------------
471 ! SPH: Changed int to INTEGER (from INTEGER(iprec))
472 ! Subroutine err_fatal
473 ! This subroutine is for fatal errors.
474 ! The first argument is a string, and there are optional arguments for
475 ! character, real, integer and logical variables.
476 ! (The user should use KEYWORDs for the optional arguments)
477 ! When called, err_fatal prints the first argument, and all of the
478 ! optional arguments, and then STOPs the program.
479 !-------------------------------------------------------------------------------
480  SUBROUTINE err_fatal(string, char, real1, int, log)
481 ! Argument Declaration
482  CHARACTER(LEN=*), INTENT(IN) :: string
483  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: char
484  REAL(rprec), OPTIONAL, INTENT(IN) :: real1
485  INTEGER, OPTIONAL, INTENT(IN) :: int
486  LOGICAL, OPTIONAL, INTENT(IN) :: log
487 
488 ! Local variable declarations
489  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
490 
491 ! Start of executable code
492  WRITE (*,fmt) 'FATAL ERROR: ',string
493 
494  IF(PRESENT(char)) THEN
495  WRITE (*,*) ' char argument = ', char
496  END IF
497 
498  IF(PRESENT(real1)) THEN
499  WRITE (*,*) ' real argument = ', real1
500  END IF
501 
502  IF(PRESENT(int)) THEN
503  WRITE (*,*) ' integer argument = ', int
504  END IF
505 
506  IF(PRESENT(log)) THEN
507  WRITE (*,*) ' logical argument = ', log
508  END IF
509 
510  stop 'program terminated by err_fatal'
511  END SUBROUTINE err_fatal
512 
513 !-------------------------------------------------------------------------------
514 ! Warning
515 !-------------------------------------------------------------------------------
516 
517 !-------------------------------------------------------------------------------
518 ! Subroutine err_warn
519 ! This subroutine is for warnings. Execution is not stopped.
520 ! The first argument is a string, and there are optional arguments for
521 ! character, real, integer and logical variables.
522 ! (The user should use KEYWORDs for the optional arguments)
523 ! When called, err_warn prints the first argument, and all of the
524 ! optional arguments, and then returns.
525 !-------------------------------------------------------------------------------
526  SUBROUTINE err_warn(string, char, real, int, log)
527 ! Argument Declaration
528  CHARACTER(LEN=*), INTENT(IN) :: string
529  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: char
530  REAL(rprec), OPTIONAL, INTENT(IN) :: real
531  INTEGER, OPTIONAL, INTENT(IN) :: int
532  LOGICAL, OPTIONAL, INTENT(IN) :: log
533 
534 ! Local variable declarations
535  CHARACTER(LEN=*), PARAMETER :: fmt='(1x,a,/,1x,a)'
536 
537 ! Start of executable code
538  WRITE (*,fmt) 'WARNING ERROR: ',string
539 
540  IF(PRESENT(char)) THEN
541  WRITE (*,*) ' char argument = ', char
542  END IF
543 
544  IF(PRESENT(real)) THEN
545  WRITE (*,*) ' real argument = ', real
546  END IF
547 
548  IF(PRESENT(int)) THEN
549  WRITE (*,*) ' integer argument = ', int
550  END IF
551 
552  IF(PRESENT(log)) THEN
553  WRITE (*,*) ' logical argument = ', log
554  END IF
555 
556  RETURN
557  END SUBROUTINE err_warn
558 
559 
560 !*******************************************************************************
561 ! SECTION IV. Input-Output Utilities
562 !*******************************************************************************
563 !-------------------------------------------------------------------------------
564 !-------------------------------------------------------------------------------
565  SUBROUTINE svdproducts(b,svprod,numzeros)
566 
567 ! This subroutine takes as its first argument an arbitrary real matrix B.
568 ! It's purpose is to find the variable in column-space that is
569 ! "most redundant"
570 
571 ! It returns a vector of singular value products, computed by eliminating
572 ! individual columns of B, and finding the product of the Singular Values (SV)
573 ! for the resulting column-reduced matrix.
574 
575 ! For example, suppose a matrix B has 13 columns, and svprod(7) is the maximum
576 ! of all the SV products. Thus eliminating column 7 yields the reduced matrix
577 ! with the largest SV product. Variable 7 in the column space is then
578 ! the "most redundant" variable.
579 
580 ! Note that when B is a normalized Jacobian matrix, a surface of
581 ! constant-chi-squared in the column-space is an
582 ! ellipsoid, and the volume of the ellipsoid is proportional to the
583 ! reciprocal of the product of the singular values.
584 
585 ! There is a problem if there are TWO (or more) variables that essentially
586 ! give ZERO singular values. (For example, if B has 13 columns, and
587 ! columns 7 and 9 are both zero.) Then the SV-product array will all be zero, and
588 ! won't be able to distinguish the "most redundant" variable.
589 ! A solution to this problem is to keep track of the number of zero SVs.
590 ! These are stored in the numzeros array.
591 ! Then the column number with the MINIMUM number of zero singular values
592 ! will be (one of) the "most-redundant" variables.
593 
594 ! The length of the SV product vector must be equal to the number of columns of B.
595 ! The length of the numzeros vector must be equal to the number of columns of B
596 ! JDH 2008-02-21, 24
597 ! JDH 2008-05-19 - CHanged for SV ratios to SV product value
598 
599  USE stel_kinds
600 
601  IMPLICIT NONE
602 
603 ! Declare Arguments
604  REAL(rprec), DIMENSION(:,:), INTENT(inout) :: b
605  REAL(rprec), DIMENSION(:), INTENT(inout) :: svprod
606  INTEGER, DIMENSION(:), INTENT(inout) :: numzeros
607 
608 ! Declare local variables
609  INTEGER, DIMENSION(2) :: dimlens
610  INTEGER :: nrowb, ncolb, nrow, ncol, minrowcol, l_work_svd, ier1
611  INTEGER :: jelim, info_svd
612  REAL(rprec) :: svp
613  REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: c
614  REAL(rprec), PARAMETER :: tiny = 1.e-14_rprec
615  REAL(rprec), PARAMETER :: verytiny = 1.e-28_rprec
616  REAL(rprec), DIMENSION(:), ALLOCATABLE :: work_svd, svec
617  CHARACTER(len=*), PARAMETER :: sub_name = &
618  & 'svdproducts: '
619 
620 ! Start of executable code
621 
622 ! Array sizes
623  dimlens = shape(b)
624  nrowb = dimlens(1)
625  ncolb = dimlens(2)
626  CALL assert(nrowb .ge. 2,sub_name // 'nrowb too small')
627  CALL assert(ncolb .ge. 2,sub_name // 'ncolb too small')
628  CALL assert_eq(ncolb,SIZE(svprod),sub_name // 'svprod wrong size')
629  CALL assert_eq(ncolb,SIZE(numzeros),sub_name // &
630  & 'numzeros wrong size')
631 
632 ! Allocate space for the number-columns-reduced-by-one arrays
633  nrow = nrowb
634  ncol = ncolb - 1
635  minrowcol = min(nrow,ncol)
636  l_work_svd = 5 * max(nrow,ncol)
637  ALLOCATE(work_svd(l_work_svd), stat = ier1)
638  CALL assert_eq(0,ier1,sub_name // 'Allocate work_svd')
639  ALLOCATE(c(nrow,ncol), stat = ier1)
640  CALL assert_eq(0,ier1,sub_name // 'Allocate c')
641  ALLOCATE(svec(minrowcol), stat = ier1)
642  CALL assert_eq(0,ier1,sub_name // 'Allocate svec')
643 
644 ! Loop over the column to be eliminated
645  DO jelim = 1,ncolb
646  c(1:nrow,1:jelim-1) = b(1:nrow,1:jelim-1)
647  c(1:nrow,jelim:ncolb-1) = b(1:nrow,jelim+1:ncolb)
648 
649  CALL dgesvd('None','None',nrow,ncol,c,nrow, &
650  & svec,c,nrow,c,ncol,work_svd,l_work_svd,info_svd)
651  CALL assert_eq(0,info_svd,sub_name // 'dgesvd problem')
652  svp = product(svec)
653  numzeros(jelim) = count(svec < tiny)
654  svprod(jelim) = svp
655  END DO
656  RETURN
657  END SUBROUTINE svdproducts
658 
659 !-------------------------------------------------------------------------------
660 !-------------------------------------------------------------------------------
661  SUBROUTINE most_redundant(a,ncol_array,svprod_array,j_col_elim)
662 
663 ! This subroutine orders the variables in the column-space of a matrix A from
664 ! "most redundant" to "least redundant". Redundancy is measured by an increase
665 ! in the product of singular values when the column is eliminated.
666 
667 ! Arguments (Input)
668 ! A Input: An array with nrow rows and ncol columns
669 ! ncol_array Integer array (ncol): number of columns of A remaining
670 ! svprod_array Real array (ncol): singular value product
671 ! j_col_elim Integer array (ncol): index of the column of A
672 ! (in the ORIGINAL ORDERING) that was eliminated most recently
673 !
674 ! The subroutine makes repeated calls to the related subroutine svdproducts.
675 !
676 ! JDH 2008-02-21
677 ! JDH 2008-05-19 - Changed from SV ratios to SV products.
678 
679  USE stel_kinds
680 
681  IMPLICIT NONE
682 
683 !-------------------------------------------------------------------------------
684 ! Declare Arguments
685 !-------------------------------------------------------------------------------
686  REAL(rprec), DIMENSION(:,:), INTENT(inout) :: a
687  REAL(rprec), DIMENSION(:), INTENT(inout) :: svprod_array
688  INTEGER, DIMENSION(:), INTENT(inout) :: ncol_array, j_col_elim
689 
690 !-------------------------------------------------------------------------------
691 ! Declare local variables
692 !-------------------------------------------------------------------------------
693  REAL(rprec), PARAMETER :: tiny = 1.e-14_rprec
694  REAL(rprec), PARAMETER :: verytiny = 1.e-28_rprec
695 ! Array dimensions, error status, indices, etc
696  INTEGER, DIMENSION(2) :: dimlens
697  INTEGER :: nrowa, ncola, nrow, ncol, minrowcol, ier1, ncolb
698  INTEGER :: i, ncolelim, minnz, k, kk
699 ! For calling the SVD subroutine
700  REAL(rprec), DIMENSION(:), ALLOCATABLE :: work_svd, svec
701  INTEGER :: l_work_svd, info_svd
702 ! Arrays for the call to svdproducts
703  REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: atemp, b
704  REAL(rprec), DIMENSION(:), ALLOCATABLE :: svprod
705  INTEGER, DIMENSION(:), ALLOCATABLE :: numzeros
706 ! Keeping track of the j-k indices, locations
707  INTEGER, DIMENSION(1) :: k_minnz_a, k_maxprod_a
708  INTEGER, DIMENSION(:), ALLOCATABLE :: j_now
709 !
710  REAL(rprec) :: maxprod
711 
712  CHARACTER(len=*), PARAMETER :: sub_name = &
713  & 'most_redundant: '
714 
715 !-------------------------------------------------------------------------------
716 ! Start of executable code
717 !-------------------------------------------------------------------------------
718 
719 ! Array sizes
720  dimlens = shape(a)
721  nrowa = dimlens(1)
722  ncola = dimlens(2)
723  CALL assert(nrowa .ge. 2,sub_name // 'nrowa too small')
724  CALL assert(ncola .ge. 2,sub_name // 'ncola too small')
725  CALL assert_eq(ncola,SIZE(ncol_array),sub_name // &
726  & 'ncol_array wrong size')
727  CALL assert_eq(ncola,SIZE(svprod_array),sub_name // &
728  & 'svprod_array wrong size')
729  CALL assert_eq(ncola,SIZE(j_col_elim),sub_name // &
730  & 'j_col_elim wrong size')
731 
732 ! Allocations for local arrays
733  nrow = nrowa
734  ncol = ncola
735  minrowcol = min(nrow,ncol)
736  l_work_svd = 5 * max(nrow,ncol)
737  ALLOCATE(work_svd(l_work_svd), stat = ier1)
738  CALL assert_eq(0,ier1,sub_name // 'Allocate work_svd')
739  ALLOCATE(atemp(nrow,ncol),b(nrow,ncol), stat = ier1)
740  CALL assert_eq(0,ier1,sub_name // 'Allocate atemp, b')
741  ALLOCATE(svec(minrowcol), stat = ier1)
742  CALL assert_eq(0,ier1,sub_name // 'Allocate svec')
743  ALLOCATE(svprod(ncola), stat = ier1)
744  CALL assert_eq(0,ier1,sub_name // 'Allocate svprod')
745  ALLOCATE(numzeros(ncola), stat = ier1)
746  CALL assert_eq(0,ier1,sub_name // 'Allocate numzeros')
747  ALLOCATE(j_now(ncola), stat = ier1)
748  CALL assert_eq(0,ier1,sub_name // 'Allocate j_now')
749 
750 ! All Columns - do SVD and find ratio
751  b = a
752  CALL dgesvd('None','None',nrow,ncol,b,nrow, &
753  & svec,b,nrow,b,ncol,work_svd,l_work_svd,info_svd)
754  CALL assert_eq(0,info_svd,sub_name // 'dgesvd problem')
755 
756  ncol_array(1) = ncola
757  svprod_array(1) = product(svec)
758  j_col_elim(1) = 0
759 
760 ! Initialize array of j-indices
761 ! Used to convert from k-index (current column number, B matrix)
762 ! to j-index (original column number, A matrix)
763  DO i = 1,ncola
764  j_now(i) = i
765  END DO
766 
767 ! Loop over the number of columns to be eliminated
768  atemp = a
769  DO ncolelim = 1,ncola-2
770  ncolb = ncola + 1 - ncolelim
771  b(1:nrow,1:ncolb) = atemp(1:nrow,1:ncolb)
772  CALL svdproducts(b(1:nrow,1:ncolb),svprod(1:ncolb), &
773  & numzeros(1:ncolb))
774  minnz = minval(numzeros(1:ncolb))
775  k_minnz_a = minloc(numzeros(1:ncolb))
776  maxprod = maxval(svprod(1:ncolb))
777  k_maxprod_a = maxloc(svprod(1:ncolb))
778  IF (minnz .gt. 0) THEN
779  k = k_minnz_a(1)
780  ELSE
781  k = k_maxprod_a(1)
782  ENDIF
783 ! WRITE(*,*) 'products', svprod(1:ncolb)
784 ! WRITE(*,*) 'numzeros', numzeros(1:ncolb)
785  ncol_array(ncolelim + 1) = ncola - ncolelim
786  svprod_array(ncolelim + 1) = maxprod
787  j_col_elim(ncolelim + 1) = j_now(k)
788  DO kk = k,ncola - ncolelim + 1
789  j_now(kk) = j_now(kk + 1)
790  atemp(1:nrow,kk) = atemp(1:nrow,kk + 1)
791  END DO
792  END DO
793 
794 ! Define last elements. Make o choice between last two variables.
795 ! Put the last two variables into j_col_elim and
796 ! into the (real) svprod_array.
797  ncol_array(ncola) = 1
798  svprod_array(ncola) = j_now(2)
799  j_col_elim(ncola) = j_now(1)
800 
801  RETURN
802  END SUBROUTINE most_redundant
803 
804 !-------------------------------------------------------------------------------
811 !-------------------------------------------------------------------------------
812  FUNCTION to_integer(real_value)
813  USE stel_kinds
814  use, INTRINSIC :: iso_c_binding
815 
816  IMPLICIT NONE
817 
818 ! Declare Arguments
819  INTEGER (C_INT64_T) :: to_integer
820  REAL (dp), INTENT(in) :: real_value
821 
822 ! Local variables
823  REAL (dp) :: as_double
824  INTEGER (C_INT64_T) :: as_int
825 
826  equivalence(as_double, as_int)
827 
828 ! Start of executable code.
829  as_double = real_value
830  to_integer = as_int
831 
832  END FUNCTION
833 
834  END MODULE v3_utilities
v3_utilities::assert_eq
Definition: v3_utilities.f:62
v3_utilities::assert
Definition: v3_utilities.f:55
mpi_inc
Umbrella module avoid multiple inlcudes of the mpif.h header.
Definition: mpi_inc.f:11