EMPIRE DA  v1.9.1
Data assimilation codes using EMPIRE communication
 All Classes Files Functions Variables Pages
4denvar_fcn.f90
Go to the documentation of this file.
1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 !!! Time-stamp: <2016-10-18 14:58:46 pbrowne>
3 !!!
4 !!! subroutine to provide objective function and gradient for var
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 
31 subroutine fcn( n, x, f, g )
32  implicit none
33  integer,intent(in) :: n
34  real(kind=kind(1.0d0)), dimension(n), intent(in) :: x
36  real(kind=kind(1.0d0)), intent(out) :: f
37  real(kind=kind(1.0d0)), dimension(n), intent(out) :: g
39 
40  call fourdenvar_fcn(n,x,f,g)
41  print*,'function = ',f
42  print*,'gradient = ',g
43 end subroutine fcn
44 
45 
105 subroutine fourdenvar_fcn(n, v, f, g )
106  use comms
107  implicit none
108  include 'mpif.h'
109  integer, parameter :: rk = kind(1.0d0)
110  integer, intent(in) :: n
112  real(kind=rk), dimension(n), intent(in) :: v
114  real(kind=rk), intent(out) :: f
115  real(kind=kind(1.0d0)), dimension(n), intent(out) :: g
117  logical :: leave
118 
119 
120  !need this executed by all processes on pf_member_comm
121  if(pf_ens_rank .eq. 0) then
122 
123  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
124  call fourdenvar_fcn_master(n, v, f, g,leave)
125  else
126 
127  if(pf_member_rank .eq. 0) then
128  call fourdenvar_fcn_master(n, v, f, g,leave)
129  else
130  do
131  call fourdenvar_fcn_master(n, v, f, g,leave)
132  if(leave) exit
133  end do
134  end if
135  end if
136 
137  else !(pf_ens_rank != 0)
138 
139  do
140  call fourdenvar_fcn_slave(n, v,leave)
141  if(leave) exit
142  end do
143  end if
144 end subroutine fourdenvar_fcn
145 
146 
153 subroutine convert_control_to_state(n,v,stateDim,x)
154  use comms
155  use fourdenvardata
156  implicit none
157  include 'mpif.h'
158  integer, parameter :: rk = kind(1.0d0)
159  integer, intent(in) :: n
160  real(kind=rk), dimension(n), intent(in) :: v
162  integer, intent(in) :: stateDim
163  real(kind=rk), dimension(stateDim), intent(out) :: x
165  real(kind=rk), dimension(stateDim) :: tempx
166  integer :: particle,mpi_err
167 
168 
169  !communicate v to all the mpi processes
170  call mpi_bcast(v,n,mpi_double_precision,&
171  0,pf_mpi_comm,mpi_err)
172 
173 
174  !now do x = X0*v
175  tempx = 0.0d0
176  do particle = 1,cnt
177  if(pfrank .ne. 0) then
178  tempx = tempx + x0(:,particle )*v(particles(particle ))
179  elseif(particle .gt. 1) then
180  tempx = tempx + x0(:,particle-1)*v(particles(particle-1))
181  end if
182  end do
183 
184 
185  !reduce this to all processors
186  call mpi_allreduce(tempx,x,statedim,mpi_double_precision,mpi_sum,&
187  &pf_mpi_comm,mpi_err)
188 
189 
190  ! now add the background term
191  x = x+xb
192 
193 end subroutine convert_control_to_state
194 
195 
196 
197 
198 subroutine fourdenvar_fcn_master(n,v,f,g,leave)
199  use output_empire, only : emp_e
200  use comms
201  use var_data
202  use fourdenvardata
203  use timestep_data
204  use sizes, only : state_dim
205  implicit none
206  include 'mpif.h'
207  integer, parameter :: rk = kind(1.0d0)
208  integer, intent(in) :: n
210  real(kind=rk), dimension(n), intent(in) :: v
212  real(kind=rk), intent(out) :: f
213  real(kind=kind(1.0d0)), dimension(n), intent(out) :: g
215  logical, intent(out) :: leave
216  real(kind=kind(1.0d0)), dimension(n) :: tempg
217  integer :: t
218  integer :: tag
219  real(kind=rk), dimension(:), allocatable :: y
220  real(kind=rk), dimension(:,:), allocatable :: hxt
221  real(kind=rk), dimension(state_dim) :: xdet
222  real(kind=rk), dimension(:), allocatable :: RY_HMX
223  real(kind=rk) :: ft
224  real(kind=rk) :: temp,sumhxtRY_HMX
225  integer :: message,mpi_err,particle
226  integer :: ensemble_comm
227 
228  leave = .false.
229  if(comm_version .eq. 1 .or. comm_version .eq. 2) then
230  ensemble_comm = pf_mpi_comm
231  elseif(comm_version .eq. 3) then
232  ensemble_comm = pf_ens_comm
233  else
234  write(emp_e,*) 'error. comm_version ',comm_version,'in fourdenvar&
235  &_fcn_master'
236  write(emp_e,*) 'stopping'
237  stop
238  end if
239 
240 
241  !tell the other mpi processes to continue in this function...
242  message = -1
243  call mpi_bcast(message,1,mpi_integer,0,pf_mpi_comm,mpi_err)
244 
245  if(pf_member_rank .ne. 0 .and. message .eq. 0) then
246  !master process has told us to stop.
247  leave = .true.
248  return
249  end if
250 
251  if(comm_version .eq. 3) then
252  call mpi_bcast(v,n,mpi_double_precision,0,pf_member_comm,mpi_err)
253  end if
254 
255  !initialise f as background term
256  f = 0.5d0*sum(v*v)*real(m-1,rk)
257 
258 
259  !initialise tempg, the gradient, to zero
260  tempg = 0.0d0
261 
262 
263  !convert control variable v into model state:
264  call convert_control_to_state(n,v,state_dim,xdet)
265 
266 
267  !now make xt centered on xdet, the optimization state
268  xt(:,1) = xdet(:)
269  if(cnt .gt. 1) then
270  do particle = 2,cnt
271  xt(:,particle) = x0(:,particle-1) + xdet(:)
272  end do
273  end if
274 
275 
276  !enter the model timestep loop
277  do t = 1,vardata%total_timesteps
278 
279  !advance model to timestep t
280  if(t == 1) then
281  tag = 2
282  else
283  tag = 1
284  end if
285 
286  call send_all_models(state_dim,cnt,xt,tag)
287 
288  call recv_all_models(state_dim,cnt,xt)
289 
290 
291 
292  !check if we have observations this timestep
293  if(vardata%ny(t) .gt. 0) then
294 
296 
297  !if observations exist then allocate data
298  allocate( y(vardata%ny(t)))
299  allocate( hxt(vardata%ny(t),cnt))
300  allocate(ry_hmx(vardata%ny(t)))
301 
302  !now let us compute the ensemble perturbation matrix
303 
304  !first we get the optimization soln to all other processes
305  xdet = xt(:,1)
306  call mpi_bcast(xdet,state_dim,mpi_double_precision,&
307  0,ensemble_comm,mpi_err)
308 
309 
310  !subtract the optimization solution to form the perturbation matrix
311  if(cnt .gt. 1) then
312  do particle = 2,cnt
313  xt(:,particle) = (xt(:,particle) - xdet(:))
314  end do
315  end if
316 
317 
318  !get model equivalent of observations, store
319  !in variable hxt
320  call h(vardata%ny(t),cnt,xt,hxt,t)
321 
322 
323  !add xdet back to the perturbation matrix to regain full ensemble
324  if(cnt .gt. 1) then
325  do particle = 2,cnt
326  xt(:,particle) = xt(:,particle) + xdet(:)
327  end do
328  end if
329 
330 
331  !read in the data
332  call get_observation_data(y,t)
333 
334 
335  !compute difference in obs and model obs
336  y = y - hxt(:,1)
337 
338 
339  !compute R_i^{-1}( y_i - H_i M_i X)
340  call solve_r(vardata%ny(t),1,y,ry_hmx,t)
341 
342 
343  !pass this data to all other processes in the ensemble
344  call mpi_bcast(ry_hmx,vardata%ny(t),mpi_double_precision,&
345  0,ensemble_comm,mpi_err)
346 
347 
348  !compute part of objective function corresponding
349  !to the observations
350  ft = sum(y*ry_hmx)
351  if(comm_version .eq. 3) then
352  temp = ft
353  call mpi_reduce(temp,ft,1,mpi_double_precision,mpi_sum&
354  &,0,pf_member_comm,mpi_err)
355  end if
356 
357 
358  !now compute the gradient part
359  !-[H_i(X_i)]^TR_i^{-1}[Y_HMX]
360  if(cnt .gt. 1) then
361  do particle = 2,cnt
362 
363  sumhxtry_hmx = sum(hxt(:,particle)*ry_hmx)
364  if(comm_version .eq. 3) then
365  !sum(hxt(:,particle),RY_HMX) needs summing
366  temp = sumhxtry_hmx
367  call mpi_allreduce(temp,sumhxtry_hmx,1&
368  &,mpi_double_precision,mpi_sum&
369  &,pf_member_comm,mpi_err)
370  end if
371 
372  tempg(particles(particle)-1) =&
373  & tempg(particles(particle)-1) &
374  &- sumhxtry_hmx
375  end do
376  end if
377 
378 
379  !deallocate data
380  deallocate(y)
381  deallocate(hxt)
382  deallocate(ry_hmx)
383 
384 
385  !update objective function with observation component
386  !at this timestep
387  f = f + 0.5d0*ft
388  end if
389 
390  end do !end of the model timestep loop
391 
392 
393  !reduce tempg to the master processor
394  call mpi_reduce(tempg,g,n,mpi_double_precision,mpi_sum&
395  &,0,ensemble_comm,mpi_err)
396 
397 
398  !add gradient of background term to g
399  g = g + v*real(m-1,rk)
400 
401 
402 end subroutine fourdenvar_fcn_master
403 
404 subroutine fourdenvar_fcn_slave(n,v,leave)
405  use output_empire, only : emp_e
406  use comms
407  use var_data
408  use fourdenvardata
409  use timestep_data
410  use sizes, only : state_dim
411  implicit none
412  include 'mpif.h'
413  integer, parameter :: rk = kind(1.0d0)
414  integer, intent(in) :: n
416  real(kind=rk), dimension(n), intent(in) :: v
418  logical, intent(out) :: leave
419  real(kind=kind(1.0d0)), dimension(n) :: tempg
420  real(kind=kind(1.0d0)), dimension(n) :: g
421  integer :: t
422  integer :: tag
423  real(kind=rk), dimension(:,:), allocatable :: hxt
424  real(kind=rk), dimension(state_dim) :: xdet
425  real(kind=rk), dimension(:), allocatable :: RY_HMX
426  integer :: message,mpi_err,particle
427  integer :: ensemble_comm
428 
429  leave = .false.
430 
431  !listen to the bcast.
432  call mpi_bcast(message,1,mpi_integer,0,pf_mpi_comm,mpi_err)
433  if(message .eq. -1) then !compute the gradient etc
434 
435 
436  !convert control variable to into model state
437  !necessary here as some info only stored on this
438  !process
439  call convert_control_to_state(n,v,state_dim,xdet)
440 
441  !now make xt centered on xdet, the optimization state
442  do particle = 1,cnt
443  xt(:,particle) = x0(:,particle) + xdet(:)
444  end do
445 
446 
447  !enter the model timestep loop
448  do t = 1,vardata%total_timesteps
449 
450  !advance model to timestep t
451  if(t == 1) then
452  tag = 2
453  else
454  tag = 1
455  end if
456 
457  call send_all_models(state_dim,cnt,xt,tag)
458 
459  call recv_all_models(state_dim,cnt,xt)
460 
461 
462  !check if we have observations this timestep
463  if(vardata%ny(t) .gt. 0) then
464 
465 
466  !if observations exist then allocate data
467  allocate( hxt(vardata%ny(t),cnt))
468  allocate(ry_hmx(vardata%ny(t)))
469 
470  !now let us compute the ensemble perturbation matrix
471 
472  !first we get the optimization soln from process 0
473  call mpi_bcast(xdet,state_dim,mpi_double_precision,&
474  0,ensemble_comm,mpi_err)
475 
476  !subtract the optimization solution to form the
477  !perturbation matrix
478  do particle = 1,cnt
479  xt(:,particle) = xt(:,particle) - xdet(:)
480  end do
481 
482 
483  !get model equivalent of observations, store
484  !in variable hxt
485  call h(vardata%ny(t),cnt,xt,hxt,t)
486 
487 
488  !add xdet back to the perturbation matrix to regain
489  !full ensemble
490  do particle = 1,cnt
491  xt(:,particle) = xt(:,particle) + xdet(:)
492  end do
493 
494 
495  !get RY_HMX from master process
496  call mpi_bcast(ry_hmx,vardata%ny(t),mpi_double_precision,&
497  0,ensemble_comm,mpi_err)
498 
499 
500  !now compute the gradient part
501  ![H_i(X_i)]^TR_i^{-1}[RY_HMX]
502  do particle = 2,cnt
503  tempg(particles(particle)) = tempg(particles(particle)) &
504  &- sum(hxt(:,particle)*ry_hmx)
505  end do
506 
507 
508  !deallocate data
509  deallocate(hxt)
510  deallocate(ry_hmx)
511 
512  end if
513  end do
514  !reduce tempg to the master processor
515  call mpi_reduce(tempg,g,n,mpi_double_precision,mpi_sum&
516  &,0,ensemble_comm,mpi_err)
517 
518  elseif(message .eq. 0) then
519  leave = .true. !leave this function
520  else !this shouldnt happen so is an error
521  write(emp_e,*) '4DEnVar ERROR: mpi_bcast had unknown integer&
522  & value',message
523  stop 9
524  end if
525 
526 end subroutine fourdenvar_fcn_slave
subroutine convert_control_to_state(n, v, stateDim, x)
a subroutine to convert the optimization control variable to a model state vector ...
subroutine solve_r(obsDim, nrhs, y, v, t)
subroutine to take an observation vector y and return v in observation space.
subroutine send_all_models(stateDim, nrhs, x, tag)
subroutine to send all the model states to the models
Definition: comms.f90:945
subroutine fourdenvar_fcn_slave(n, v, leave)
Module containing EMPIRE coupling data.
Definition: comms.f90:57
Module that stores the information about the outputting from empire.
module holding data specific for 4denvar, not var itself. this is necessary because of the difference...
Module that stores the information about the timestepping process.
subroutine recv_all_models(stateDim, nrhs, x)
subroutine to receive all the model states from the models after
Definition: comms.f90:993
Module that stores the dimension of observation and state spaces.
Definition: sizes.f90:29
subroutine fourdenvar_fcn_master(n, v, f, g, leave)
subroutine h(obsDim, nrhs, x, hx, t)
subroutine to take a full state vector x and return H(x) in observation space.
subroutine fourdenvar_fcn(n, v, f, g)
subroutine to provide the objective function and gradient for 4dEnVar.
subroutine fcn(n, x, f, g)
This is the subroutine which the optimization routines call to get the objective function value and i...
Definition: 4denvar_fcn.f90:31
subroutine timestep_data_set_next_ob_time(ob_time)
subroutine to set the next observation timestep
subroutine get_observation_data(y, t)
Subroutine to read observation from a file .
module holding data for variational problems
Definition: var_data.f90:29