EMPIRE DA  v1.9.1
Data assimilation codes using EMPIRE communication
 All Classes Files Functions Variables Pages
eakf_analysis.f90
Go to the documentation of this file.
1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 !!! Time-stamp: <2014-09-18 10:09:54 pbrowne>
3 !!!
4 !!! {one line to give the program's name and a brief idea of what it does.}
5 !!! Copyright (C) 2014 Philip A. Browne
6 !!!
7 !!! This program is free software: you can redistribute it and/or modify
8 !!! it under the terms of the GNU General Public License as published by
9 !!! the Free Software Foundation, either version 3 of the License, or
10 !!! (at your option) any later version.
11 !!!
12 !!! This program is distributed in the hope that it will be useful,
13 !!! but WITHOUT ANY WARRANTY; without even the implied warranty of
14 !!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 !!! GNU General Public License for more details.
16 !!!
17 !!! You should have received a copy of the GNU General Public License
18 !!! along with this program. If not, see <http://www.gnu.org/licenses/>.
19 !!!
20 !!! Email: p.browne @ reading.ac.uk
21 !!! Mail: School of Mathematical and Physical Sciences,
22 !!! University of Reading,
23 !!! Reading, UK
24 !!! RG6 6BB
25 !!!
26 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27 subroutine eakf_analysis(num_hor,num_ver,this_hor,this_ver,boundary,x,N&
28  &,statedim,obsdim,rho)
29 implicit none
30 integer, parameter :: rk = kind(1.0d0)
31 integer, intent(in) :: N,stateDim,obsDim
32 real(kind=rk), dimension(stateDim,N), intent(inout) :: x
33 integer, intent(in) :: num_hor,num_ver,this_hor,this_ver,boundary
34 real(kind=rk), intent(in) :: rho
35 
36 real(kind=rk), dimension(obsDim) :: y
37 real(kind=rk), dimension(obsDim) :: d,dd
38 real(kind=rk), dimension(stateDim) :: mean_x
39 real(kind=rk), dimension(obsDim) :: Hmean_xf
40 real(kind=rk), dimension(stateDim,N) :: Xpf
41 real(kind=rk), dimension(N) :: G,S,dn
42 real(kind=rk), dimension(stateDim,N) :: F,FG,FGU,Xpa
43 real(kind=rk), dimension(obsDim,N) :: HFG,Ysf
44 real(kind=rk), dimension(N,obsDim) :: YsfT
45 real(kind=rk), dimension(obsDim,obsDim) :: VT
46 real(kind=rk), dimension(N,N) :: WT,U
47 integer :: LWORK1,LWORK2,INFO
48 real(kind=rk), dimension(:), allocatable :: WORK1,WORK2
49 integer :: i
50 
51 call get_local_observation_data(num_hor,num_ver,this_hor,this_ver,boundary,obsdim,y)
52 
53 
54 mean_x = 0.0_rk
55 do i = 1,n
56  mean_x = mean_x + x(:,i)
57 end do
58 mean_x = mean_x/real(n,rk)
59 
60 do i = 1,n
61  xpf(:,i) = (x(:,i) - mean_x)/sqrt(real(n-1,rk))
62 end do
63 
64 !compute the svd
65 !JOBU='S' the first min(m,n) columns of U (the left singular
66 ! vectors) are returned in the array U;
67 !JOBVT='S' the first min(m,n) rows of V**T (the right singular
68 ! vectors) are returned in the array VT;
69 !M=stateDim The number of rows of the input matrix A. M >= 0.
70 !
71 !N=N The number of columns of the input matrix A. N >= 0.
72 !
73 !A=Xpf DOUBLE PRECISION array, dimension (LDA,N)
74 ! On entry, the M-by-N matrix A.
75 ! On exit,
76 ! if JOBU .ne. 'O' and JOBVT .ne. 'O', the contents of A
77 ! are destroyed.
78 !LDA=stateDim The leading dimension of the array A. LDA >= max(1,M)
79 !
80 !S=G DOUBLE PRECISION array, dimension (min(M,N))
81 ! The singular values of A, sorted so that S(i) >= S(i+1).
82 !
83 !U=F (output) DOUBLE PRECISION array, dimension (LDU,UCOL)
84 ! (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'.
85 ! if JOBU = 'S', U contains the first min(m,n) columns of U
86 ! (the left singular vectors, stored columnwise);
87 !
88 !LDU=stateDim The leading dimension of the array U. LDU >= 1; if
89 ! JOBU = 'S' or 'A', LDU >= M.
90 !
91 !VT=WT DOUBLE PRECISION array, dimension (LDVT,N)
92 ! if JOBVT = 'S', VT contains the first min(m,n) rows of
93 ! V**T (the right singular vectors, stored rowwise);
94 !
95 !LDVT=N The leading dimension of the array VT. LDVT >= 1; if
96 ! JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N)
97 !
98 !WORK=WORK1 DOUBLE PRECISION array, dimension (MAX(1,LWORK))
99 ! On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
100 ! if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged
101 ! superdiagonal elements of an upper bidiagonal matrix B
102 ! whose diagonal is in S (not necessarily sorted). B
103 ! satisfies A = U * B * VT, so it has the same singular values
104 ! as A, and singular vectors related by U and VT.
105 !
106 !LWORK=LWORK1 The dimension of the array WORK.
107 ! LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)).
108 ! For good performance, LWORK should generally be larger.
109 !
110 ! If LWORK = -1, then a workspace query is assumed; the routine
111 ! only calculates the optimal size of the WORK array, returns
112 ! this value as the first entry of the WORK array, and no error
113 ! message related to LWORK is issued by XERBLA.
114 !
115 !INFO=INFO (output) INTEGER
116 ! = 0: successful exit.
117 ! < 0: if INFO = -i, the i-th argument had an illegal value.
118 ! > 0: if DBDSQR did not converge, INFO specifies how many
119 ! superdiagonals of an intermediate bidiagonal form B
120 ! did not converge to zero. See the description of WORK
121 ! above for details.
122 
123 lwork1 = 2*max( 3*n+statedim, 5*n )
124 allocate(work1(lwork1))
125 
126 call dgesvd('S','S',statedim,n,xpf,statedim,g,f,statedim,wt,n,work1,lwork1,info)
127 if(info .ne. 0) then
128  print*,'First SVD failed with info = ',info
129  print*,'FYI work(1) = ',work1(1)
130  stop
131 end if
132 deallocate(work1)
133 
134 !FG = F*G
135 do i = 1,n
136  fg(:,i) = f(:,i)*g(i)
137 end do
138 
139 call h(n,fg,hfg)
140 call solve_rhalf(n,hfg,ysf)
141 
142 ysft = transpose(ysf)
143 
144 !JOBU='A' (input) CHARACTER*1
145 ! Specifies options for computing all or part of the matrix U:
146 ! = 'A': all M columns of U are returned in array U:
147 !
148 !JOBVT='A' (input) CHARACTER*1
149 ! Specifies options for computing all or part of the matrix
150 ! V**T:
151 ! = 'A': all N rows of V**T are returned in the array VT;
152 !M=N (input) INTEGER
153 ! The number of rows of the input matrix A. M >= 0.
154 !
155 !N=obsDim (input) INTEGER
156 ! The number of columns of the input matrix A. N >= 0.
157 !
158 !A=YsfT (input/output) DOUBLE PRECISION array, dimension (LDA,N)
159 ! On entry, the M-by-N matrix A.
160 ! On exit,
161 ! if JOBU .ne. 'O' and JOBVT .ne. 'O', the contents of A
162 ! are destroyed.
163 !
164 !LDA=N (input) INTEGER
165 ! The leading dimension of the array A. LDA >= max(1,M).
166 !
167 !S=S (output) DOUBLE PRECISION array, dimension (min(M,N))
168 ! The singular values of A, sorted so that S(i) >= S(i+1).
169 !
170 !U=U (output) DOUBLE PRECISION array, dimension (LDU,UCOL)
171 ! (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'.
172 ! If JOBU = 'A', U contains the M-by-M orthogonal matrix U;
173 !
174 !LDU=N (input) INTEGER
175 ! The leading dimension of the array U. LDU >= 1; if
176 ! JOBU = 'S' or 'A', LDU >= M.
177 !
178 !VT=VT (output) DOUBLE PRECISION array, dimension (LDVT,N)
179 ! If JOBVT = 'A', VT contains the N-by-N orthogonal matrix
180 ! V**T;
181 ! if JOBVT = 'S', VT contains the first min(m,n) rows of
182 ! V**T (the right singular vectors, stored rowwise);
183 ! if JOBVT = 'N' or 'O', VT is not referenced.
184 !
185 !LDVT=obsDim (input) INTEGER
186 ! The leading dimension of the array VT. LDVT >= 1; if
187 ! JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N).
188 !
189 !WORK=WORK2 (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
190 ! On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
191 ! if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged
192 ! superdiagonal elements of an upper bidiagonal matrix B
193 ! whose diagonal is in S (not necessarily sorted). B
194 ! satisfies A = U * B * VT, so it has the same singular values
195 ! as A, and singular vectors related by U and VT.
196 !
197 !LWORK=LWORK2 (input) INTEGER
198 ! The dimension of the array WORK.
199 ! LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)).
200 ! For good performance, LWORK should generally be larger.
201 !
202 ! If LWORK = -1, then a workspace query is assumed; the routine
203 ! only calculates the optimal size of the WORK array, returns
204 ! this value as the first entry of the WORK array, and no error
205 ! message related to LWORK is issued by XERBLA.
206 !
207 ! INFO (output) INTEGER
208 
209 lwork2 = 2*max( 3*n+obsdim, 5*n )
210 allocate(work2(lwork2))
211 
212 call dgesvd('A','A',n,obsdim,ysft,n,s,u,n,vt,obsdim,work2,lwork2,info)
213 
214 if(info .ne. 0) then
215  print*,'Second SVD failed with info = ',info
216  print*,'FYI work(1) = ',work2(1)
217  stop
218 end if
219 deallocate(work2)
220 
221 !FGU = FG*U
222 call dgemm('N','N',statedim,n,n,1.0_rk,fg,statedim,u,n,0.0_rk,fgu,statedim)
223 
224 do i = 1,n
225  fgu(:,i) = fgu(:,i) / sqrt(1.0_rk + s(i)**2)
226 end do
227 
228 !Xpa = FGU * W'
229 call dgemm('N','N',statedim,n,n,1.0_rk,fgu,statedim,wt,n,0.0_rk,xpa,statedim)
230 
231 
232 call h(1,mean_x,hmean_xf)
233 hmean_xf = y - hmean_xf
234 call solve_rhalf(1,hmean_xf,d)
235 
236 !dd = V'*d
237 call dgemv('N',obsdim,obsdim,1.0_rk,vt,obsdim,d,1,0.0_rk,dd,1)
238 
239 do i = 1,n
240  dd(i) = dd(i)/ sqrt(1.0_rk + s(i)**2)
241 end do
242 
243 !d = S*dd
244 !this now makes a vector of size N, call it dn
245 dn = 0.0_rk
246 dn = s*dd(1:n)
247 
248 !mean_xa = mean_x + FGU*d
249 !note here I am reusing mean_x to be mean_xa
250 call dgemv('N',statedim,n,1.0_rk,fgu,statedim,dn,1,1.0_rk,mean_x,1)
251 
252 !xa = mean_xa*ones(1,N) + sqrt(N-1)*Xpa;
253 !x = mean_x*ones(1,N) + sqrt(N-1)*Xpa;
254 
255 do i = 1,n
256  x(:,i) = mean_x + sqrt(real(n-1,rk))*xpa(:,i)
257 end do
258 
259 
260 end subroutine eakf_analysis
261 
subroutine eakf_analysis(num_hor, num_ver, this_hor, this_ver, boundary, x, N, stateDim, obsDim, rho)
subroutine h(obsDim, nrhs, x, hx, t)
subroutine to take a full state vector x and return H(x) in observation space.
subroutine get_local_observation_data(num_hor, num_ver, this_hor, this_ver, boundary, obsDim, y)
subroutine solve_rhalf(obsdim, nrhs, y, v, t)
subroutine to take an observation vector y and return v in observation space.