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