EMPIRE DA  v1.9.1
Data assimilation codes using EMPIRE communication
 All Classes Files Functions Variables Pages
resample.f90
Go to the documentation of this file.
1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 !!! Time-stamp: <2016-10-18 15:12:58 pbrowne>
3 !!!
4 !!! Subroutine to perform Universal Importance Resampling
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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28 subroutine resample
29  !this takes pf%phi with corresponding weights pf%weight
30  !which are stored as -log(w_i)
31  !and returns pf%phi which has been resampled with completely equal weights
32 
33 
34  use output_empire, only : emp_e
35  use pf_control
36  use random
37  use sizes
38  use comms
39  implicit none
40  include 'mpif.h'
41  integer, parameter :: rk = kind(1.0d0)
42  integer :: i,old,j,dupepos,dupe,particle,k
43  real(kind=rk), dimension(pf%nens) :: cumweights
44  integer, dimension(pf%nens) :: new,tobereplaced,brandnew
45  logical :: in
46  real(kind=rk) :: point,draw
47  integer :: mpi_err
48  integer, dimension(2*pf%nens) :: requests
49  integer :: summ,destination,source
50  integer, allocatable, dimension(:,:) :: statuses
51  logical :: flag
52 
53  integer :: ensemble_comm
54 
55  !print*,'in resample, pf%weight = ',pf%weight
56 
57  select case(comm_version)
58  case(1,2,4)
59  ensemble_comm = pf_mpi_comm
60  case(3)
61  ensemble_comm = pf_ens_comm
62  case default
63  write(emp_e,*) 'EMPIRE VERSION ',comm_version,' NOT SUPPORTED IN RESAMP&
64  &LE'
65  write(emp_e,*) 'THIS IS AN ERROR. STOPPING'
66  stop '-24'
67  end select
68  !gather the weights onto the master processor of the particle filter
69 
70  call mpi_gatherv(pf%weight(gbldisp(pfrank+1)+1:gbldisp(pfrank+1)+pf%count&
71  &),pf%count,mpi_double_precision,pf%weight&
72  &,gblcount,gbldisp,mpi_double_precision,0,ensemble_comm,mpi_err)
73 
74 
75  !we have to just draw one random number, so this task is best
76  !performed solely by the master processor...
77 
78  !print*,'ahoy ',pf%weight
79  if(pfrank == 0 ) then
80  !check for NaN in the weight
81  if(.not. all(pf%weight .eq. pf%weight)) then
82  do i = 1,pf%nens
83  if(pf%weight(i) .ne. pf%weight(i)) then
84  write(emp_e,*) 'EMPIRE ERROR in resample.f90'
85  write(emp_e,*) 'Particle ',i,' has weight ',pf%weight(i)
86  write(emp_e,*) 'stopping now'
87  end if
88  end do
89  stop
90  end if
91 
92  !normalise the weights and store them as the actual values.
93  !print*,'seriously: ',pf%weight
94  pf%weight = exp(-pf%weight + minval(pf%weight) )
95  !print*,'un-normalised weights: ',pf%weight
96  pf%weight = pf%weight/sum(pf%weight)
97  !print*,'weights = ',pf%weight
98  !compute the cumulative weights, so cumweights(j) = sum_i=1^j weights(i)
99  cumweights = 0.0_rk
100  cumweights(1) = pf%weight(1)
101  do i = 2,pf%nens
102  cumweights(i) = cumweights(i-1) + pf%weight(i)
103  end do
104 
105  !print*,'cumweights'
106  !print*,cumweights
107 
108  !now make the draw of the single random variable
109  !distributed normally between 0 and 1/(number of ensemble members)
110  call random_number(draw)
111  draw = draw/pf%nens
112 
113 
114 
115  new = 0
116  old = 1
117 
118  !for each particle, compute the POINT given by the
119  !random draw.
120  do particle = 1,pf%nens
121  point = real(particle-1,rk)/pf%nens + draw
122  ! print*,particle,point
123  !Step through the weights of each of the particles
124  !and find the 'bin' which it lies in.
125  !store this in the array NEW.
126  do
127  if(point .lt. cumweights(old)) then
128  new(particle) = old
129  exit
130  else
131  old = old + 1
132  end if
133  end do
134  end do
135 
136 
137  !now we need to determine which particles have to be replaced:
138  !initialise this array to something stupid:
139  tobereplaced = -1
140 
141  !loop over each particle
142  do i = 1,pf%nens
143  in = .false.
144  !go through the array NEW and if it does not exist
145  !in that array, then mark the array TOBEREPLACED
146  !with the index of said particle
147  do j= 1,pf%nens
148  if(i .eq. new(j)) then
149  in = .true.
150  exit
151  end if
152  end do
153  if(.not. in) tobereplaced(i) = i
154  end do
155 
156  !dupepos is a counter storing the position of duplicated
157  dupepos = 1
158  !generate the array BRANDNEW = [1,2,3,...,N]
159  brandnew = (/ (i,i=1,pf%nens) /)
160 
161  !loop through all the particles
162  do i = 1,pf%nens
163  if(tobereplaced(i) .ne. -1) then
164  !if the particle is to be replaced then
165  !find the particle which has been duplicated
166  do k = dupepos,pf%nens
167  if(new(k) .eq. new(k+1)) then
168  dupe = new(k+1)
169  dupepos = k+1
170  exit
171  end if
172  end do
173  !place this duplicated particle into the place
174  !in the array BRANDNEW that it corresponds to
175  brandnew(tobereplaced(i)) = dupe
176  end if
177  end do
178  !print*,'##################################'
179  !print*,brandnew
180  !print*,'##################################'
181 
182 
183  end if
184 
185  !now the master processor can send the array
186  !BRANDNEW to all the other processors
187  call mpi_bcast(brandnew,pf%nens,mpi_integer,0,pf_mpi_comm,mpi_err)
188  !print*,brandnew
189 
190 
191 
192  !check to see if any of this processors particles are being
193  !replaced. if so, call the mpi receive
194  k=0
195  do i = 1,pf%count
196  particle = pf%particles(i)
197  if(particle .ne. brandnew(particle)) then
198  print*,'replacing particle ',particle,'with particle ',brandnew(particle)
199  !pf%psi(:,particle) = pf%psi(:,brandnew(particle))
200  !pf%psi(:,i) = pf%psi(:,????)
201  k=k+1
202  print*,'pfrank ',pfrank,'going to receive particle ',i,' from ta&
203  &g ',brandnew(particle)
204  !the tag will correspond to where it is coming from.
205  !who cares where the source was.
206  call mpi_irecv(pf%psi(:,i),state_dim,mpi_double_precision&
207  &,mpi_any_source,brandnew(particle),ensemble_comm,requests(k)&
208  &,mpi_err)
209  end if
210  end do
211  !print*,'all the recvs have started'
212 
213  !print*,'pf%particles(1) = ',pf%particles(1),'pf%particles(pf%count) = &
214  ! &',pf%particles(pf%count)
215  !print*,'brandnew(pf%count) = ',brandnew(pf%count)
216 
217  !now, go through all the particles and see if we have to send
218  !any of them to some process to replace that particle
219  do i = 1,pf%nens
220  !print*,'i = ',i,'brandnew(i) = ',brandnew(i)
221  !check if the new particle is in the range of the particles
222  !stored on this process and if it is to be sent somewhere
223  if(brandnew(i) .ge. pf%particles(1) .and. brandnew(i) .le.&
224  & pf%particles(pf%count) .and. brandnew(i) .ne. i ) then
225  !compute the destination!
226  !this is the pfrank corresponding to ensemble member i
227  destination = 0
228  summ = 0
229  do j = 1,npfs
230  ! print*,'computing destination j = ',j
231  if(i .le. summ+gblcount(j)) then
232  ! print*,i,summ+gblcount(j),j-1
233  destination = j-1
234  exit
235  else
236  summ = summ + gblcount(j)
237  ! print*,'summ now is ',summ
238  end if
239  end do
240 
241  k=k+1
242  print*,'destination'
243  print*,destination
244  print*,'brandnew(i)'
245  print*,brandnew(i)
246 
247  !let us find the source to be sent...
248  do j = 1,pf%count
249  if(pf%particles(j) .eq. brandnew(i)) then
250  source = j
251  exit
252  end if
253  end do
254 
255 
256  print*,k
257  print*,'going to send ',brandnew(i),'with tag',brandnew(i)
258  print*,'from pfrank ',pfrank,' to destination ',destination
259 
260  print*,'the source number is ',source
261 !!$ call mpi_isend(pf%psi(:,brandnew(i)),state_dim&
262 !!$ &,mpi_double_precision,destination,brandnew(i),pf_mpi_comm&
263 !!$ &,requests(k),mpi_err)
264 
265  call mpi_isend(pf%psi(:,source),state_dim&
266  &,mpi_double_precision,destination,brandnew(i),ensemble_comm&
267  &,requests(k),mpi_err)
268 
269  end if
270  end do
271  !print*,'waiting'
272 
273  !now as all the sends and receives were non-blocking, we must wait
274  ! for them to complete.
275  if(k.gt.0) then
276  print*,'going into mpi_waitall with pfrank = ',pfrank
277  ALLOCATE( statuses(mpi_status_size,k) )
278  print*,'going into mpi_testall'
279  flag = .false.
280  do
281  if(flag) exit
282  call mpi_testall(k,requests(1:k),flag,statuses,mpi_err)
283  end do
284  print*,'mpi testall finished with flag ',flag
285  !call mpi_waitall(k,requests(1:k),statuses(:,1:k),mpi_err)
286  deallocate(statuses)
287  print*,'did the mpi_waitall on pfrank = ',pfrank
288  end if
289  print*,'hit the barrier'
290  call mpi_barrier(pf_mpi_comm,mpi_err)
291 
292  !we have just resampled, so by construction the particles
293  !have equal weights.
294  pf%weight = 1.0_rk/real(pf%nens,rk)
295  pf%weight = -log(pf%weight)
296  !print*,'finished resampling'
297  !print*,'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
298 end subroutine resample
subroutine resample
Subroutine to perform Universal Importance Resampling.
Definition: resample.f90:28
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
module pf_control holds all the information to control the the main program
Definition: pf_control.f90:29
A module for random number generation from the following distributions:
Definition: random_d.f90:22