V3FIT
svdsolveuv.f
1  SUBROUTINE svdsolveuv(m, n, mp, np, wcut, file, a, b, x)
2  USE stel_kinds
3  IMPLICIT NONE
4 C-----------------------------------------------
5 C D u m m y A r g u m e n t s
6 C-----------------------------------------------
7  INTEGER m, n, mp, np
8  REAL(rprec) wcut
9  CHARACTER file*(*)
10  REAL(rprec), DIMENSION(mp,np) :: a
11  REAL(rprec), DIMENSION(n) :: x
12  REAL(rprec), DIMENSION(m) :: b
13 C-----------------------------------------------
14 C L o c a l P a r a m e t e r s
15 C-----------------------------------------------
16  REAL(rprec) :: zero = 0
17 C-----------------------------------------------
18 C L o c a l V a r i a b l e s
19 C-----------------------------------------------
20  INTEGER :: n1, nonzero, nlast, istat, i, j, iunit
21  REAL(rprec), ALLOCATABLE :: u(:,:), w(:), v(:,:)
22  REAL(rprec) :: wmax, wcuta, udotb
23 C-----------------------------------------------
24 
25 c Solves Matrix equation A X = B for X using SVD method
26 c Allows supression of weights, storage and recall of answers
27 c Uses svd routines from numerical recipes
28 c Prashant Valanju (Sept 1998) pvalanju@mail.utexas.edu
29 
30 c Almost same as SvdSolveB except this one stores U, W, V
31 c rather than basis vectors.
32 c Use this one when you want to change both B and weights for fixed A
33 
34 c Inputs:
35 c A(M,N) - Matrix with physical dimensions (Mp,Np)
36 c B(N) - R.H.S. of A X = B
37 c M - Number of rows of A to use
38 c N - Number of columns of A to use
39 c Mp,NP - Storage dimensions of A(Mp,Np)
40 c Wcut - Cutoff parameter
41 c If Wcut = 0, writes answers into "file", all weights are kept
42 c If Wcut < 0, reads previous answers from "file",
43 c and uses -Wcut for weights to keep
44 c If 0 < Wcut < 1 : Cuts off weights with w(i)/wmax < wcut
45 c Use this to cut off small weights, does calculation
46 c If Wcut = integer > 1, keeps Wcut weights, does calculation
47 c Use this to cut off fixed number of weights
48 c Output:
49 c X(N) - Solution of A X = B
50 c
51  n1 = n
52 
53 c ALLOCATE local arrays
54  ALLOCATE (u(mp,np), w(np), v(np,np), stat=istat)
55  IF (istat .eq. 0) THEN !have enough memory
56  iunit = 41
57 
58  x(:n1) = zero !zero answer from previous CALL
59  wcuta = abs(wcut)
60 c...............................
61 c If Wcut < 0 use precalculated weights to get answer fast
62 c use wcuta = ABS(wcut) for everything
63 c If any error happens while reading "file", do full svd calculation
64  IF (wcut .lt. 0) THEN !Read file from previous calculation
65  CALL safe_open(iunit, istat, file, 'old', 'formatted')
66  IF (istat .ne. 0) GOTO 98
67  READ (iunit, *, err=98)
68  READ (iunit, *, err=98)
69  READ (iunit, *, err=98) m, n, nonzero
70  DO i = 1, n !Read exactly the same way they were written
71  READ (iunit, *, err=98) w(i) !READ i-th weight
72  DO j = 1, n
73  READ (iunit, *, err=98) v(j,i)
74  END DO
75  DO j = 1, m
76  READ (iunit, *, err=98) u(j,i)
77  END DO
78  END DO
79  CLOSE(unit=iunit)
80 
81  GOTO 99 !Use U, w, V matrices to calculate X
82  ENDIF !End of precalculated branch Wcut < 0
83  98 CONTINUE
84 c.......................................
85 c If Wcut .ge. 0, do full svd calculation
86 c Initialize all to zero to wipe out effects of old call
87  DO j = 1, n
88  w(j) = zero !Zero all weights
89  u(:m,j) = a(:m,j) !Because U will be changed by svdcmp
90  v(:n,j) = zero
91  END DO
92 
93  CALL svdcmp (u, m, n, mp, np, w, v) !Do SVD decomposition
94 
95 c Sort weights and matrices with DECREASING weights
96 c Permute weight w(i) AND column vectors U(*,i), V(*,i) at the same time
97  CALL sortsvd (m, n, mp, np, w, u, v)
98 
99 c Find the number of nonzero weights (already dcreasing ordered)
100  DO nonzero = n, 1, -1
101 c !Found first nonzero weight, get out
102  IF (w(nonzero) .ne. 0) EXIT
103  END DO
104  IF (nonzero .le. 0) GOTO 999
105 
106 c............................................
107 c Decide how many weights to keep
108  99 CONTINUE
109  IF (wcuta .gt. 1) THEN
110  nlast = wcuta
111  ELSE !cutoff small weights
112  wmax = w(1) !weights are already ordered
113  nlast = 0
114  DO i = 1, nonzero
115  IF (w(i) .gt. wmax*wcuta) THEN
116  nlast = nlast + 1 !accept this weight
117  ELSE
118  GOTO 96
119  END IF
120  END DO
121  END IF
122 
123 c Find solution X and basis vectors (put into columns of V)
124 c This is the NR SVBKSB routine
125  96 CONTINUE
126  IF (nlast.le.0 .or. nlast.gt.nonzero) nlast = nonzero
127  DO i = 1, nlast !Calc i-th coeff (U.b/w) for noNonzero w(i)
128 c First calculate i-th coeff (U(i)*b/w(i)) in the SUM in eq 14.3.17 (NR)
129 c !Dot product of i-th column of U with B
130 c !summed over all plasma points
131  udotb = sum(u(:m,i)*b(:m))
132 c !=(Ui.b/wi) in eq 14.3.17, saves many divisions
133  udotb = udotb/w(i)
134 c Now run DOwn the i-th column of the vector V(j,i)
135 c !j-th entry (row) of vectors in eq 14.3.17
136 c !add it to the j-th entry of X
137  x(:n) = x(:n) + udotb*v(:n,i)
138 c !This did the svdbksb, faster than NR
139  END DO !and also calculated the basis vectors
140 
141 c............................................
142 c Write ALL weights and U, V into SVD file (IF Wcut=0)
143  IF (wcut .eq. 0) THEN
144  CALL safe_open(iunit, istat, file, 'unknown', 'formatted')
145  WRITE (iunit, *) 'Max w = ', w(1), ', Min w = ', w(nonzero)
146  WRITE (iunit, *) 'Ratio = ', w(1)/w(nonzero)
147  WRITE (iunit, *) m, n, nonzero
148  DO i = 1, n
149  WRITE (iunit, *) w(i) !WRITE i-th weight
150  DO j = 1, n
151  WRITE (iunit, *) v(j,i)
152  END DO
153  DO j = 1, m
154  WRITE (iunit, *) u(j,i)
155  END DO
156  END DO
157  CLOSE(unit=iunit)
158  END IF
159 c................................................
160  END IF
161  999 CONTINUE
162 
163  DEALLOCATE (u, w, v, stat=istat)
164 
165  END SUBROUTINE svdsolveuv