EMPIRE DA  v1.9.1
Data assimilation codes using EMPIRE communication
 All Classes Files Functions Variables Pages
etkf_analysis.f90
Go to the documentation of this file.
1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 !!! Time-stamp: <2014-09-25 11:46:38 pbrowne>
3 !!!
4 !!! Ensemble transform Kalman filter
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 ! $RCSfile: etkf_analysis.f90,v $
28 ! $Revision: 1.6 $
29 ! $Date: 2013/12/12 03:58:54 $
30 
34 subroutine etkf_analysis(num_hor,num_ver,this_hor,this_ver,boundary,x,N,stateDim,obsDim,rho)
35 
36 implicit none
37 integer, parameter :: rk = kind(1.0d0)
38 
39 integer, intent(in) :: N,stateDim,obsDim
40 ! Forecast ensemble on entry, analysis ensemble on exit
41 real(kind=rk), dimension(stateDim,N), intent(inout) :: x
42 ! The observation
43 !real(kind=rk), dimension(obsDim), intent(in) :: y
44 real(kind=rk), dimension(obsDim) :: y
45 ! Inflation parameter; forecast perturbations will be scaled by 1+rho
46 ! if rho is present
47 real(kind=rk), intent(in) :: rho
48 ! controls for localisation
49 integer, intent(in) :: num_hor,num_ver,this_hor,this_ver,boundary
50 
51 ! Local variables for the SVD
52 integer :: r
53 real(kind=rk), dimension(:,:), allocatable :: V
54 real(kind=rk), dimension(:), allocatable :: S
55 real(kind=rk), dimension(N,N) :: UT
56 integer :: LWORK,INFO
57 real(kind=rk), dimension(:), allocatable :: WORK
58 
59 ! Miscellaneous local variables
60 real(kind=rk), dimension(stateDim) :: mean_x
61 real(kind=rk), dimension(stateDim,N) :: Xp
62 real(kind=rk), dimension(obsDim) :: mean_yf,d,dd
63 real(kind=rk), dimension(obsDim,N) :: yf,Ysf
64 integer :: i
65 
66 call get_local_observation_data(num_hor,num_ver,this_hor,this_ver,boundary,obsdim,y)
67 
68 ! Split forecast ensemble into mean and perturbation matrix, inflating
69 ! if necessary
70 mean_x = sum(x,dim=2)/real(n,rk)
71 do i = 1,n
72  xp(:,i) = x(:,i) - mean_x
73 end do
74 !if (present(rho)) then
75 xp = (1.0_rk + rho) * xp
76 do i = 1,n
77  x(:,i) = mean_x + xp(:,i)
78 end do
79 !end if
80 xp = xp/sqrt(real(n-1,rk))
81 
82 ! Calculate forecast observations, split into mean and ensemble
83 ! perturbation matrix, scale perturbations by inverse square root of
84 ! observation covariance
85 !call H(N,stateDim,obsDim,x,yf)
86 call h_local(num_hor,num_ver,this_hor,this_ver,boundary,n,statedim,x&
87  &,obsdim,yf)
88 mean_yf = sum(yf,dim=2)/real(n,rk)
89 do i = 1,n
90  yf(:,i) = yf(:,i) - mean_yf
91 end do
92 yf = yf/sqrt(real(n-1,rk))
93 !call solve_rhalf(N,obsDim,yf,Ysf)
94 call solve_rhalf_local(num_hor,num_ver,this_hor,this_ver,boundary,n&
95  &,obsdim,yf,ysf)
96 
97 ! Compute the SVD
98 r = min(obsdim,n)
99 allocate(v(obsdim,r))
100 allocate(s(r))
101 lwork = 2*max( 3*r+max(obsdim,n), 5*r )
102 allocate(work(lwork))
103 call dgesvd('S','A',obsdim,n,ysf,obsdim,s,v,obsdim,ut,n,work,lwork,info)
104 if(info .ne. 0) then
105  print*,'SVD failed with INFO = ',info
106  print*,'FYI WORK(1) = ',work(1)
107  stop
108 end if
109 deallocate(work)
110 
111 ! Compute product of forecast ensemble perturbation matrix and U. We
112 ! store the result in x, which we here call X to distinguish this
113 ! secondary use of the variable.
114 call dgemm('N','T',statedim,n,n,1.0d0,xp,statedim,ut,n,0.0d0,x,statedim)
115 
116 ! Build up analysis ensemble mean (to be stored in mean_x); done now
117 ! because we shall be reusing X shortly
118 d = y - mean_yf
119 !call solve_rhalf(1,obsDim,d,dd)
120 call solve_rhalf_local(num_hor,num_ver,this_hor,this_ver,boundary,1&
121  &,obsdim,d,dd)
122 ! Only the first r elements of d are in use from here on
123 call dgemv('T',obsdim,r,1.0d0,v,obsdim,dd,1,0.0d0,d,1)
124 d(1:r) = s * d(1:r) / (1.0_rk + s**2)
125 ! Only the first r columns of X are used in the following
126 call dgemv('N',statedim,r,1.0d0,x,statedim,d,1,1.0d0,mean_x,1)
127 
128 ! Build up analysis ensemble perturbation matrix
129 do i = 1,r
130  x(:,i) = x(:,i) / sqrt(1.0_rk + s(i)**2)
131 end do
132 call dgemm('N','N',statedim,n,n,1.0d0,x,statedim,ut,n,0.0d0,xp,statedim)
133 
134 ! Put ensemble mean and perturbation matrix back together
135 x = sqrt(real(n-1,rk))*xp
136 do i = 1,n
137  x(:,i) = mean_x + x(:,i)
138 end do
139 
140 end subroutine etkf_analysis
subroutine h_local(num_hor, num_ver, this_hor, this_ver, boundary, nrhs, stateDim, x, obsDim, y)
subroutine etkf_analysis(num_hor, num_ver, this_hor, this_ver, boundary, x, N, stateDim, obsDim, rho)
subroutine to perform the ensemble transform Kalman filter
subroutine get_local_observation_data(num_hor, num_ver, this_hor, this_ver, boundary, obsDim, y)
subroutine solve_rhalf_local(num_hor, num_ver, this_hor, this_ver, boundary, nrhs, obsDim, y, v)