EMPIRE DA  v1.9.1
Data assimilation codes using EMPIRE communication
 All Classes Files Functions Variables Pages
letks.f90
Go to the documentation of this file.
1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 !!! Time-stamp: <2016-10-20 10:46:14 pbrowne>
3 !!!
4 !!! Module for doing things related to the LETKS: Local Ensemble
5 !!! Kalman Transform Smoother
6 !!! Copyright (C) 2015 Philip A. Browne
7 !!!
8 !!! This program is free software: you can redistribute it and/or modify
9 !!! it under the terms of the GNU General Public License as published by
10 !!! the Free Software Foundation, either version 3 of the License, or
11 !!! (at your option) any later version.
12 !!!
13 !!! This program is distributed in the hope that it will be useful,
14 !!! but WITHOUT ANY WARRANTY; without even the implied warranty of
15 !!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 !!! GNU General Public License for more details.
17 !!!
18 !!! You should have received a copy of the GNU General Public License
19 !!! along with this program. If not, see <http://www.gnu.org/licenses/>.
20 !!!
21 !!! Email: p.browne @ reading.ac.uk
22 !!! Mail: School of Mathematical and Physical Sciences,
23 !!! University of Reading,
24 !!! Reading, UK
25 !!! RG6 6BB
26 !!!
27 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28 
31 module letks_data
32  implicit none
34  integer :: red_obsdim
35  real(kind=kind(1.0d0)), allocatable, dimension(:,:) :: usiut
36  real(kind=kind(1.0d0)), allocatable, dimension(:) :: ud
37  end type letks_local
38 
39  type(letks_local), allocatable, dimension(:) :: lsd
40 
41 contains
42  subroutine allocate_letks(N)
43  integer, intent(in) :: N
44  allocate(lsd(n))
45  end subroutine allocate_letks
46 
47  subroutine deallocate_letks()
48  deallocate(lsd)
49  end subroutine deallocate_letks
50 
54  subroutine letks_filter_stage
55  use output_empire, only : emp_e
56  use comms
57  use pf_control
58  use sizes
59  implicit none
60  integer, parameter :: rk = kind(1.0d0)
61 
62  !!> Forecast ensemble on entry, analysis ensemble on exit
63  !real(kind=rk), dimension(stateDimension,N), intent(inout) :: x
64  real(kind=rk), dimension(state_dim,pf%count) :: x_p
65 
67  real(kind=rk), dimension(obs_dim) :: y
68 
69  ! Local variables for the SVD
70  integer :: r
71  real(kind=rk), dimension(:,:), allocatable :: V
72  real(kind=rk), dimension(:), allocatable :: S
73  real(kind=rk), dimension(pf%nens,pf%nens) :: UT
74  !SMOOTHER ONLY:
75  real(kind=rk), dimension(pf%nens,pf%nens) :: U
76  integer :: LWORK,INFO
77  real(kind=rk), dimension(:), allocatable :: WORK
78 
79  ! Miscellaneous local variables
80  real(kind=rk), dimension(state_dim) :: mean_x
81  real(kind=rk), dimension(:), allocatable :: mean_xa
82  real(kind=rk), dimension(state_dim,pf%count) :: Xp_p
83  !real(kind=rk), dimension(stateDimension,N) :: Xp
84  real(kind=rk), dimension(:,:), allocatable :: Xp
85  real(kind=rk), dimension(:,:), allocatable :: Xa
86  real(kind=rk), dimension(obs_dim) :: mean_yf,d,dd
87  real(kind=rk), dimension(obs_dim_g) :: dd_g
88  real(kind=rk), dimension(obs_dim,pf%nens) :: yf,Ysf
89  real(kind=rk), dimension(obs_dim_g,pf%nens) :: Ysf_g
90  real(kind=rk), dimension(obs_dim,pf%count) :: yf_p
91  integer :: i,j,number_gridpoints
92 
93  !variables for localisation
94  real(kind=rk) :: dist
95  real(kind=rk), parameter :: maxscal=exp(8.0d0)
96  real(kind=rk),dimension(obs_dim_g) :: scal
97  logical, dimension(obs_dim_g) :: yes
98  integer :: red_obsdim
99  real(kind=rk), allocatable, dimension(:,:) :: Ysf_red
100  real(kind=rk), allocatable, dimension(:) :: dd_red
101  integer :: stateDim !generally 1 for the letkf
102 
103  !variables for mpi
104  integer :: mpi_err
105  integer, dimension(npfs) :: start_var,stop_var
106  integer :: ensemble_comm
107  include 'mpif.h'
108 
109  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
110  ensemble_comm = pf_mpi_comm
111  elseif(comm_version .eq. 3) then
112  ensemble_comm = pf_ens_comm
113  else
114  write(emp_e,*) 'EMPIRE VERSION ',comm_version,' NOT SUPPORTED IN letks_filter_state'
115  write(emp_e,*) 'THIS IS AN ERROR. STOPPING'
116  stop '-24'
117  end if
118 
119 
120  call get_observation_data(y,pf%timestep)
121 
122  ! Split forecast ensemble into mean and perturbation matrix, inflating
123  ! if necessary
124  ! mean_x will only be the sum of state vectors on this mpi process
125  mean_x = sum(pf%psi,dim=2)
126 
127  !send mean_x to all processes and add up to get global sum
128  call mpi_allreduce(mpi_in_place,mean_x,state_dim,mpi_double_precision&
129  &,mpi_sum,ensemble_comm,mpi_err)
130 
131  !now divide by the total number of ensemble members to make it a true
132  !mean
133  mean_x = mean_x/real(pf%nens,rk)
134 
135  ! compute the ensemble perturbation matrix for those ensemble members
136  ! stored on this local mpi process
137  do i = 1,pf%count
138  xp_p(:,i) = pf%psi(:,i) - mean_x
139  end do
140 
141  ! inflate the ensemble perturbation matrix
142  xp_p = (1.0_rk + pf%rho) * xp_p
143  ! store the local state vectors back in x_p
144  do i = 1,pf%count
145  x_p(:,i) = mean_x + xp_p(:,i)
146  end do
147 
148  ! make the local ensemble perturbation matrix the correct scale
149  xp_p = xp_p/sqrt(real(pf%nens-1,rk))
150 
151  ! Calculate forecast observations, split into mean and ensemble
152  ! perturbation matrix, scale perturbations by inverse square root of
153  ! observation covariance
154 
155  ! first apply observation operator only to local state vectors
156  ! on this mpi process
157  call h(obs_dim,pf%count,x_p,yf_p,pf%timestep)
158 
159 
160  ! as yf_p should be much smaller than x_p, send this to mpi processes
161  ! need to send round all yf_p and store in yf on all processes
162  call mpi_allgatherv(yf_p,pf%count*obs_dim,mpi_double_precision,yf&
163  &,gblcount*obs_dim,gbldisp*obs_dim,mpi_double_precision&
164  &,ensemble_comm,mpi_err)
165 
166  ! compute the mean of yf
167  mean_yf = sum(yf,dim=2)/real(pf%nens,rk)
168  do i = 1,pf%nens
169  yf(:,i) = yf(:,i) - mean_yf
170  end do
171 
172  ! now make yf the forecast perturbation matrix
173  yf = yf/sqrt(real(pf%nens-1,rk))
174  ! scale yf to become ysf
175  call solve_rhalf(obs_dim,pf%nens,yf,ysf,pf%timestep)
176 
177 
178  ! now let us compute which state variables will be analysed on each
179  ! MPI process:
180  do i = 1,npfs
181  start_var(i) = (i-1)*ceiling( real(state_dim,rk)/real(npfs,rk) )+1
182  stop_var(i) = min( i*ceiling(real(state_dim,rk)/real(npfs,rk)) ,state_dim)
183  end do
184 
185  !allocate space for Xp and Xa now that we know how many grid points we consider
186  allocate(xp(stop_var(pfrank+1)-start_var(pfrank+1)+1,pf%nens))
187  allocate(xa(stop_var(pfrank+1)-start_var(pfrank+1)+1,pf%nens))
188  allocate(mean_xa(stop_var(pfrank+1)-start_var(pfrank+1)+1))
189  mean_xa = mean_x(start_var(pfrank+1):stop_var(pfrank+1))
190 
191  !now we have to get Xp filled with all the values from each process
192  do i = 1,npfs
193  number_gridpoints = stop_var(i)-start_var(i)+1
194 
195  call mpi_gatherv(xp_p(start_var(i):stop_var(i),:),& !sendbuf
196  pf%count*number_gridpoints,& !sendcount
197  mpi_double_precision,& !sendtype
198  xp,& !recvbuf
199  gblcount*number_gridpoints,& !recvcounts
200  gbldisp*number_gridpoints,& !displs
201  mpi_double_precision,& !recvtype
202  i-1,& !root
203  ensemble_comm,& !comm
204  mpi_err) !ierror
205  end do
206 
207 
208  d = y - mean_yf
209  call solve_rhalf(obs_dim,1,d,dd,pf%timestep)
210 
211  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
212  dd_g = dd
213  ysf_g = ysf
214  elseif(comm_version .eq. 3) then
215  call mpi_allgatherv(dd,obs_dim,mpi_double_precision,dd_g,obs_dims&
216  &,obs_displacements,mpi_double_precision,pf_member_comm&
217  &,mpi_err)
218  call mpi_allgatherv(ysf,obs_dim*pf%nens,mpi_double_precision&
219  &,ysf_g,obs_dims*pf%nens,obs_displacements*pf%nens&
220  &,mpi_double_precision,pf_member_comm,mpi_err)
221  else
222  print*,'should not enter here. error. stopping :('
223  end if
224 
225  !this is for serial processing
226  number_gridpoints = stop_var(pfrank+1)-start_var(pfrank+1)+1
227 
228 
229  !SMOOTHER ONLY:
230  call allocate_letks(number_gridpoints)
231 
232  !$OMP PARALLEL DO &
233  !$OMP& PRIVATE(stateDim,i,dist,scal,yes), &
234  !$OMP& PRIVATE(Ysf_red,red_obsDim,r,V,S,LWORK,WORK,INFO), &
235  !$OMP& PRIVATE(dd_red,UT,d)
236  do j = 1,number_gridpoints
237 ! print*,'j = ',j,' Xp(j,1) = ',Xp(j,1)
238  statedim = 1
239  yes = .false.
240  !let us process the observations here:
241  do i = 1,obs_dim_g
242  ! get the distance between the current state variable
243  ! j+start_var(pfrank+1)-1
244  ! and the observation i
245  ! store it as distance
246  call dist_st_ob(j+start_var(pfrank+1)-1,i,dist,pf%timestep)
247  ! compute the scaling factor based in this distance and the
248  ! length scale
249  call loc_function(1,dist,scal(i),yes(i))
250  end do
251 
252  ! count the total number of observations we shall consider for this
253  ! state variable
254  red_obsdim = count(yes)
255 
256 
257  !SMOOTHER ONLY
258  lsd(j)%red_obsdim = red_obsdim
259 
260  ! if there are no observations in range, treat this as a special case
261  if(red_obsdim .gt. 0) then
262 
263  allocate(ysf_red(red_obsdim,pf%nens))
264  !multiply by the distance matrix
265  !this line only works for diagonal R matrix...
266  ! reduce the forecast ensemble to only the observations in range
267  ! and scale by the distance function
268  do i = 1,pf%nens
269  ysf_red(:,i) = pack(ysf_g(:,i),yes)*pack(scal,yes)
270  end do
271 
272  ! Compute the SVD
273  r = min(red_obsdim,pf%nens)
274 
275  !SMOOTHER ONLY:
276  allocate(lsd(j)%Ud(pf%nens))
277  allocate(lsd(j)%USIUT(pf%nens,pf%nens))
278 
279 
280  allocate(v(red_obsdim,r))
281  allocate(s(r))
282  lwork = 2*max( 3*r+max(red_obsdim,pf%nens), 5*r )
283 
284  allocate(work(lwork))
285 
286  call dgesvd('S','A',red_obsdim,pf%nens,ysf_red,red_obsdim,s,v,red_obsdim,ut,pf%nens,work,lwork,info)
287  if(info .ne. 0) then
288  write(emp_e,*) 'EMPIRE ERROR in letks_filter_stage with t&
289  &he SVD'
290  write(emp_e,*) 'SVD failed with INFO = ',info
291  write(emp_e,*) 'FYI WORK(1) = ',work(1)
292  write(emp_e,*) 'STOPPING'
293  stop
294  end if
295  deallocate(work)
296 
297  ! Compute product of forecast ensemble perturbation matrix and U. We
298  ! store the result in xa, which we here call Xa to distinguish this
299  ! secondary use of the variable.
300  ! pick out the correct row of Xa and Xp here:
301  call dgemm('N','T',statedim,pf%nens,pf%nens,1.0d0,xp(j,:),statedim,ut,pf%nens,0.0d0,xa(j,:),statedim)
302 
303 
304  ! Build up analysis ensemble mean (to be stored in mean_x); done now
305  ! because we shall be reusing X shortly
306 
307  allocate(dd_red(red_obsdim))
308  dd_red = pack(dd_g,yes)*pack(scal,yes)
309 
310 
311  ! Only the first r elements of d are in use from here on
312  call dgemv('T',red_obsdim,r,1.0d0,v,red_obsdim,dd_red,1,0.0d0,d,1)
313 
314  d(1:r) = s * d(1:r) / (1.0_rk + s**2)
315 
316  !SMOOTHER ONLY: calculate U*d
317  call dgemv('T',r,pf%nens,1.0d0,ut,r,d(1:r),1,0.0d0&
318  &,lsd(j)%Ud,1)
319 
320 ! print*,LSD(j)%Ud,matmul(transpose(UT),d(1:r))-LSD(j)%Ud
321 ! print*,dot_product(Xa(j,:),d(1:r)) + mean_xa(j)
322 ! print*,dot_product(Xp(j,:),LSD(j)%Ud)
323 
324 
325  ! Only the first r columns of Xa are used in the following
326  call dgemv('N',statedim,r,1.0d0,xa(j,:),statedim,d,1,1.0d0,mean_xa(j),1)
327 ! print*,'j = ',j,' mean_xa(j) = ',mean_xa(j)
328 
329  ! Build up analysis ensemble perturbation matrix
330  do i = 1,r
331  xa(j,i) = xa(j,i) / sqrt(1.0_rk + s(i)**2)
332  end do
333 
334 
335  !SMOOTHER ONLY: calculate U*(S^2+I)^{-1/2}U^T
336  u = transpose(ut)
337  do i = 1,r
338  u(:,i) = u(:,i) / sqrt(1.0_rk + s(i)**2)
339  end do
340  call dgemm('N','N',pf%nens,pf%nens,pf%nens,1.0d0,u,pf%nens&
341  &,ut,pf%nens,0.0d0,lsd(j)%USIUT,pf%nens)
342 ! print*,'j = ',j,' XpUSLUT = ',matmul(Xp(j,:),LSD(j)%USIUT)
343 
344  call dgemm('N','N',statedim,pf%nens,pf%nens,1.0d0,xa(j,:),statedim,ut,pf%nens,0.0d0,xp(j,:),statedim)
345 
346 ! print*,'j = ',j,' Xp(j,:) = ',Xp(j,:)
347 
348  ! Put ensemble mean and perturbation matrix back together
349  xa(j,:) = sqrt(real(pf%nens-1,rk))*xp(j,:)
350  do i = 1,pf%nens
351  xa(j,i) = mean_xa(j) + xa(j,i)
352  end do
353 
354  !put this back into the full state vector
355  !wait it is already
356  deallocate(ysf_red)
357  deallocate(v)
358  deallocate(s)
359  deallocate(dd_red)
360 
361  else !if there are no observations near, the analysis is
362  ! just the forecast
363  do i = 1,pf%nens
364  xa(j,i) = mean_xa(j) + xp(j,i)
365  end do
366 
367  end if
368  end do
369  !$OMP END PARALLEL DO
370 
371 
372 
373  ! now we must scatter xa back into pf%psi
374  do i = 1,npfs
375 
376  number_gridpoints = stop_var(i)-start_var(i)+1
377 
378  call mpi_scatterv(xa,& !sendbuf
379  gblcount*number_gridpoints,& !sendcounts
380  gbldisp*number_gridpoints,& !displs
381  mpi_double_precision,& !sendtype
382  pf%psi(start_var(i):stop_var(i),:),& !recvbuf
383  pf%count*number_gridpoints,& !recvcount
384  mpi_double_precision,& !recvtype
385  i-1,& !root
386  ensemble_comm,& !comm
387  mpi_err) !ierror
388  end do
389 
390 
391  deallocate(mean_xa)
392  deallocate(xp)
393  deallocate(xa)
394  end subroutine letks_filter_stage
395 
396 
398  subroutine letks_increment(psi,inc)
399  use output_empire, only : emp_e
400  use comms
401  use pf_control
402  use sizes
403  implicit none
404  integer, parameter :: rk = kind(1.0d0)
405 
406 
407  real(kind=rk), intent(in), dimension(state_dim,pf%count) :: psi
408 
409  real(kind=rk), intent(out), dimension(state_dim,pf%count) :: inc
410 
411 
412 
413  !!> Forecast ensemble on entry, analysis ensemble on exit
414  !real(kind=rk), dimension(stateDimension,N), intent(inout) :: x
415  real(kind=rk), dimension(state_dim,pf%count) :: x_p
416 
417 
418  ! Local variables for the SVD
419  integer :: r
420 
421  ! Miscellaneous local variables
422  real(kind=rk), dimension(state_dim) :: mean_x
423  real(kind=rk), dimension(:), allocatable :: mean_xa
424  real(kind=rk), dimension(state_dim,pf%count) :: Xp_p
425  !real(kind=rk), dimension(stateDimension,N) :: Xp
426  real(kind=rk), dimension(:,:), allocatable :: Xp
427  real(kind=rk), dimension(:,:), allocatable :: Xa
428  integer :: i,j,number_gridpoints
429 
430  !variables for localisation
431  integer :: red_obsdim
432  integer :: stateDim !generally 1 for the letkf
433 
434  !variables for mpi
435  integer :: mpi_err
436  integer, dimension(npfs) :: start_var,stop_var
437  integer :: ensemble_comm
438  include 'mpif.h'
439 
440  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
441  ensemble_comm = pf_mpi_comm
442  elseif(comm_version .eq. 3) then
443  ensemble_comm = pf_ens_comm
444  else
445  write(emp_e,*) 'EMPIRE VERSION ',comm_version,' NOT SUPPORTED IN letks_increment'
446  write(emp_e,*) 'THIS IS AN ERROR. STOPPING'
447  stop '-24'
448  end if
449 
450 
451  ! Split forecast ensemble into mean and perturbation matrix, inflating
452  ! if necessary
453  ! mean_x will only be the sum of state vectors on this mpi process
454  mean_x = sum(psi,dim=2)
455 
456  !send mean_x to all processes and add up to get global sum
457  call mpi_allreduce(mpi_in_place,mean_x,state_dim,mpi_double_precision&
458  &,mpi_sum,ensemble_comm,mpi_err)
459 
460  !now divide by the total number of ensemble members to make it a true
461  !mean
462  mean_x = mean_x/real(pf%nens,rk)
463 
464  ! compute the ensemble perturbation matrix for those ensemble members
465  ! stored on this local mpi process
466  do i = 1,pf%count
467  xp_p(:,i) = psi(:,i) - mean_x
468  end do
469 
470  ! inflate the ensemble perturbation matrix
471  xp_p = (1.0_rk + pf%rho) * xp_p
472  ! store the local state vectors back in x_p
473  do i = 1,pf%count
474  x_p(:,i) = mean_x + xp_p(:,i)
475  end do
476 
477  ! make the local ensemble perturbation matrix the correct scale
478  xp_p = xp_p/sqrt(real(pf%nens-1,rk))
479 
480 
481  ! now let us compute which state variables will be analysed on each
482  ! MPI process:
483  do i = 1,npfs
484  start_var(i) = (i-1)*ceiling( real(state_dim,rk)/real(npfs,rk) )+1
485  stop_var(i) = min( i*ceiling(real(state_dim,rk)/real(npfs,rk)) ,state_dim)
486  end do
487 
488  !allocate space for Xp and Xa now that we know how many grid points we consider
489  allocate(xp(stop_var(pfrank+1)-start_var(pfrank+1)+1,pf%nens))
490  allocate(xa(stop_var(pfrank+1)-start_var(pfrank+1)+1,pf%nens))
491  allocate(mean_xa(stop_var(pfrank+1)-start_var(pfrank+1)+1))
492 
493 
494  mean_xa = mean_x(start_var(pfrank+1):stop_var(pfrank+1))
495 
496  !now we have to get Xp filled with all the values from each process
497  do i = 1,npfs
498  number_gridpoints = stop_var(i)-start_var(i)+1
499 
500  call mpi_gatherv(xp_p(start_var(i):stop_var(i),:),& !sendbuf
501  pf%count*number_gridpoints,& !sendcount
502  mpi_double_precision,& !sendtype
503  xp,& !recvbuf
504  gblcount*number_gridpoints,& !recvcounts
505  gbldisp*number_gridpoints,& !displs
506  mpi_double_precision,& !recvtype
507  i-1,& !root
508  ensemble_comm,& !comm
509  mpi_err) !ierror
510  end do
511 
512 
513 
514 
515  number_gridpoints = stop_var(pfrank+1)-start_var(pfrank+1)+1
516  !$OMP PARALLEL DO &
517  !$OMP& PRIVATE(stateDim,i), &
518  !$OMP& PRIVATE(red_obsDim,r)
519  do j = 1,number_gridpoints
520 ! print*,'j = ',j,' Xp(j,1) = ',Xp(j,1)
521  statedim = 1
522 
523  ! count the total number of observations we shall consider for this
524  ! state variable
525  red_obsdim = lsd(j)%red_obsdim
526 
527 
528  ! if there are no observations in range, treat this as a special case
529  if(red_obsdim .gt. 0) then
530 
531 
532  ! compute
533  r = min(red_obsdim,pf%nens)
534 
535 
536  !LOOK UP U*d(1:r), call it Ud. It has dimension pf%nens
537  ! Only the first r columns of Xp are used in the following
538  call dgemv('N',statedim,pf%nens,1.0d0,xp(j,:),statedim,lsd(j)%Ud,1,1.0d0,mean_xa(j),1)
539 
540 ! print*,'j = ',j,' mean_xa(j) = ',mean_xa(j)
541 
542  !LOOK UP U*(S^2+I)^{-1/2}U^T, call it USIUT.
543  !IT has dimension (nens,nens)
544  call dgemm('N','N',statedim,pf%nens,pf%nens,1.0d0,xp(j,:),statedim,lsd(j)%USIUT,pf%nens,0.0d0,xa(j,:),statedim)
545 
546  ! Put ensemble mean and perturbation matrix back together
547  xp(j,:) = sqrt(real(pf%nens-1,rk))*xa(j,:)
548  do i = 1,pf%nens
549  xa(j,i) = mean_xa(j) + xp(j,i)
550  end do
551 
552 
553  else !if there are no observations near, the analysis is
554  ! just the forecast
555  do i = 1,pf%nens
556  xa(j,i) = mean_xa(j) + xp(j,i)
557  end do
558 
559  end if
560  end do
561  !$OMP END PARALLEL DO
562 
563 
564 
565  ! now we must scatter xa back into pf%psi
566  do i = 1,npfs
567 
568  number_gridpoints = stop_var(i)-start_var(i)+1
569 
570  call mpi_scatterv(xa,& !sendbuf
571  gblcount*number_gridpoints,& !sendcounts
572  gbldisp*number_gridpoints,& !displs
573  mpi_double_precision,& !sendtype
574  inc(start_var(i):stop_var(i),:),& !recvbuf
575  pf%count*number_gridpoints,& !recvcount
576  mpi_double_precision,& !recvtype
577  i-1,& !root
578  ensemble_comm,& !comm
579  mpi_err) !ierror
580  end do
581 
582  inc = inc-psi
583 
584  deallocate(mean_xa)
585  deallocate(xp)
586  deallocate(xa)
587 
588 
589 
590  end subroutine letks_increment
591 end module letks_data
592 
module for doing things related to the LETKS:
Definition: letks.f90:31
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 loc_function(loctype, dis, scal, inc)
subroutine to compute a localisation weighting based on a distance
subroutine deallocate_letks()
Definition: letks.f90:47
subroutine solve_rhalf(obsdim, nrhs, y, v, t)
subroutine to take an observation vector y and return v in observation space.
subroutine letks_increment(psi, inc)
subroutine to compute the LETKS increments
Definition: letks.f90:398
module pf_control holds all the information to control the the main program
Definition: pf_control.f90:29
subroutine letks_filter_stage
subroutine to compute the data for the LETKS, so that the increments can subsquently be computed ...
Definition: letks.f90:54
subroutine get_observation_data(y, t)
Subroutine to read observation from a file .
subroutine allocate_letks(N)
Definition: letks.f90:42
subroutine dist_st_ob(xp, yp, dis, t)
subroutine to compute the distance between the variable in the state vector and the variable in the o...