EMPIRE DA  v1.9.1
Data assimilation codes using EMPIRE communication
 All Classes Files Functions Variables Pages
phalf_etkf.f90
Go to the documentation of this file.
1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 !!! Time-stamp: <2016-10-20 10:45:32 pbrowne>
3 !!!
4 !!! Routine to change an ensemble N(0,I) to N(0,P)
5 !!! Copyright (C) 2015 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 
28 
30 subroutine phalf_etkf(nrhs,x,px)
31  use output_empire, only : emp_e
32  use pf_control
33  use sizes
34  use comms
35  implicit none
36  include 'mpif.h'
37 
38  integer, parameter :: rk=kind(1.0d0)
39 
40  integer, intent(in) :: nrhs
41  real(kind=rk), dimension(state_dim,nrhs), intent(in) :: x
43  real(kind=rk), dimension(state_dim,nrhs), intent(out) :: px
45 
46  real(kind=rk), dimension(state_dim,pf%count) :: Xp_p
47  real(kind=rk), dimension(obs_dim,pf%count) :: yf_p
48  real(kind=rk), dimension(obs_dim,pf%nens) :: yf,Ysf
49  real(kind=rk), dimension(obs_dim_g,pf%nens) :: Ysf_g
50  real(kind=rk), dimension(obs_dim) :: mean_yf
51  integer, dimension(npfs) :: start_var,stop_var
52  !real(kind=rk), dimension(stateDimension,N) :: Xp
53  real(kind=rk), dimension(:,:), allocatable :: Xp
54  real(kind=rk), dimension(:,:), allocatable :: Xa
55  integer :: mpi_err
56  integer :: i,j,number_gridpoints
57 
58  integer :: red_obsdim
59  real(kind=rk), allocatable, dimension(:,:) :: Ysf_red
60 
61  ! Local variables for the SVD
62  integer :: r
63  real(kind=rk), dimension(:,:), allocatable :: V
64  real(kind=rk), dimension(:), allocatable :: S
65  real(kind=rk), dimension(pf%nens,pf%nens) :: UT
66  integer :: LWORK,INFO
67  real(kind=rk), dimension(:), allocatable :: WORK
68  integer :: stateDim
69  !!> Forecast ensemble on entry, analysis ensemble on exit
70  !real(kind=rk), dimension(stateDimension,N), intent(inout) :: x
71  real(kind=rk), dimension(state_dim,pf%count) :: x_p
72 
73  integer :: ensemble_comm
74 
75  !first lets make something N(0,Q):
76  call qhalf(nrhs,x,xp_p)
77 
78  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
79  ensemble_comm = pf_mpi_comm
80  elseif(comm_version .eq. 3) then
81  ensemble_comm = pf_ens_comm
82  else
83  write(emp_e,*) 'EMPIRE VERSION ',comm_version,' NOT SUPPORTED IN phalf_etkf'
84  write(emp_e,*) 'THIS IS AN ERROR. STOPPING'
85  stop '-24'
86  end if
87 
88 
89  !now go into the LETKF code:
90 
91  x_p = xp_p
92 
93 
94  ! Calculate forecast observations, split into mean and ensemble
95  ! perturbation matrix, scale perturbations by inverse square root of
96  ! observation covariance
97 
98  ! first apply observation operator only to local state vectors
99  ! on this mpi process
100  call h(obs_dim,pf%count,x_p,yf_p,pf%timestep)
101 
102 
103  ! as yf_p should be much smaller than x_p, send this to mpi processes
104  ! need to send round all yf_p and store in yf on all processes
105  call mpi_allgatherv(yf_p,pf%count*obs_dim,mpi_double_precision,yf&
106  &,gblcount*obs_dim,gbldisp*obs_dim,mpi_double_precision&
107  &,ensemble_comm,mpi_err)
108 
109  ! compute the mean of yf
110  mean_yf = sum(yf,dim=2)/real(pf%nens,rk)
111  do i = 1,pf%nens
112  yf(:,i) = yf(:,i) - mean_yf
113  end do
114 
115  ! now make yf the forecast perturbation matrix
116  yf = yf/sqrt(real(pf%nens-1,rk))
117  ! scale yf to become ysf
118  call solve_rhalf(obs_dim,pf%nens,yf,ysf,pf%timestep)
119 
120 
121  ! now let us compute which state variables will be analysed on each
122  ! MPI process:
123  do i = 1,npfs
124  start_var(i) = ((i-1)*state_dim)/npfs + 1
125  stop_var(i) = (i*state_dim)/npfs
126  end do
127 
128  !allocate space for Xp and Xa now that we know how many grid points we consider
129  allocate(xp(stop_var(pfrank+1)-start_var(pfrank+1)+1,pf%nens))
130  allocate(xa(stop_var(pfrank+1)-start_var(pfrank+1)+1,pf%nens))
131 
132  !now we have to get Xp filled with all the values from each process
133  do i = 1,npfs
134  number_gridpoints = stop_var(i)-start_var(i)+1
135 
136  call mpi_gatherv(xp_p(start_var(i):stop_var(i),:),& !sendbuf
137  pf%count*number_gridpoints,& !sendcount
138  mpi_double_precision,& !sendtype
139  xp,& !recvbuf
140  gblcount*number_gridpoints,& !recvcounts
141  gbldisp*number_gridpoints,& !displs
142  mpi_double_precision,& !recvtype
143  i-1,& !root
144  ensemble_comm,& !comm
145  mpi_err) !ierror
146  end do
147 
148 
149  !PAB d = y - mean_yf
150  !PAB call solve_rhalf(obs_dim,1,d,dd,pf%timestep)
151 
152  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
153  ysf_g = ysf
154  elseif(comm_version .eq. 3) then
155  call mpi_allgatherv(ysf,obs_dim*pf%nens,mpi_double_precision&
156  &,ysf_g,obs_dims*pf%nens,obs_displacements*pf%nens&
157  &,mpi_double_precision,pf_member_comm,mpi_err)
158  else
159  print*,'should not enter here. error. stopping :o('
160  end if
161 
162  !this is for serial processing
163  number_gridpoints = stop_var(pfrank+1)-start_var(pfrank+1)+1
164  !$OMP PARALLEL DO &
165  !$OMP& PRIVATE(stateDim,i), &
166  !$OMP& PRIVATE(Ysf_red,red_obsDim,r,V,S,LWORK,WORK,INFO), &
167  !$OMP& PRIVATE(UT)
168  do j = 1,number_gridpoints
169  statedim = 1
170 
171  ! count the total number of observations we shall consider for this
172  ! state variable
173  red_obsdim = obs_dim_g
174 
175 
176  allocate(ysf_red(red_obsdim,pf%nens))
177  ! reduce the forecast ensemble to only the observations in range
178  ! and scale by the distance function
179  do i = 1,pf%nens
180  ysf_red(:,i) = ysf_g(:,i)
181  end do
182 
183  ! Compute the SVD
184  r = min(red_obsdim,pf%nens)
185  allocate(v(red_obsdim,r))
186  allocate(s(r))
187  lwork = 2*max( 3*r+max(red_obsdim,pf%nens), 5*r )
188 
189  allocate(work(lwork))
190 
191  call dgesvd('S','A',red_obsdim,pf%nens,ysf_red,red_obsdim,s,v,red_obsdim,ut,pf%nens,work,lwork,info)
192  if(info .ne. 0) then
193  write(emp_e,*) 'EMPIRE ERROR in phalf_etkf.f90 with the SVD'
194  write(emp_e,*) 'SVD failed with INFO = ',info
195  write(emp_e,*) 'FYI WORK(1) = ',work(1)
196  write(emp_e,*) 'STOPPING'
197  stop
198  end if
199  deallocate(work)
200 
201  ! Compute product of forecast ensemble perturbation matrix and U. We
202  ! store the result in xa, which we here call Xa to distinguish this
203  ! secondary use of the variable.
204  ! pick out the correct row of Xa and Xp here:
205  call dgemm('N','T',statedim,pf%nens,pf%nens,1.0d0,xp(j,:),statedim,ut,pf%nens,0.0d0,xa(j,:),statedim)
206 
207 
208  ! Build up analysis ensemble perturbation matrix
209  do i = 1,r
210  xa(j,i) = xa(j,i) / sqrt(1.0_rk + s(i)**2)
211  end do
212  call dgemm('N','N',statedim,pf%nens,pf%nens,1.0d0,xa(j,:),statedim,ut,pf%nens,0.0d0,xp(j,:),statedim)
213 
214 
215  !put this back into the full state vector
216  !wait it is already
217  deallocate(ysf_red)
218  deallocate(v)
219  deallocate(s)
220 
221 
222  end do
223  !$OMP END PARALLEL DO
224 
225 
226 
227  ! now we must scatter xa back into px
228  do i = 1,npfs
229 
230  number_gridpoints = stop_var(i)-start_var(i)+1
231 
232  call mpi_scatterv(xa,& !sendbuf
233  gblcount*number_gridpoints,& !sendcounts
234  gbldisp*number_gridpoints,& !displs
235  mpi_double_precision,& !sendtype
236  px(start_var(i):stop_var(i),:),& !recvbuf
237  pf%count*number_gridpoints,& !recvcount
238  mpi_double_precision,& !recvtype
239  i-1,& !root
240  ensemble_comm,& !comm
241  mpi_err) !ierror
242  end do
243 
244 
245 
246  deallocate(xp)
247  deallocate(xa)
248 
249 
250 
251 end subroutine phalf_etkf
Module containing EMPIRE coupling data.
Definition: comms.f90:57
Module that stores the information about the outputting from empire.
Module that stores the dimension of observation and state spaces.
Definition: sizes.f90:29
subroutine h(obsDim, nrhs, x, hx, t)
subroutine to take a full state vector x and return H(x) in observation space.
subroutine phalf_etkf(nrhs, x, px)
Subroutine to go from N(0,Q) to N(0,P)
Definition: phalf_etkf.f90:30
subroutine solve_rhalf(obsdim, nrhs, y, v, t)
subroutine to take an observation vector y and return v in observation space.
module pf_control holds all the information to control the the main program
Definition: pf_control.f90:29
subroutine qhalf(nrhs, x, Qx)
subroutine to take a full state vector x and return in state space.