FV3 Bundle
ensemble_manager.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 
20 !> \brief ensemble_manager_mod
21 !!
23 
24 
25  use fms_mod, only : open_namelist_file,close_file,check_nml_error
26  use mpp_mod, only : mpp_npes, stdout, stdlog, mpp_error, fatal
27  use mpp_mod, only : mpp_pe, mpp_declare_pelist
28  use mpp_mod, only : input_nml_file
30 
31  IMPLICIT NONE
32 
33  private
34 
35  integer, parameter :: max_ensemble_size = 100
36 
37 
38  integer, allocatable, dimension(:,:) :: ensemble_pelist
39  integer, allocatable, dimension(:,:) :: ensemble_pelist_ocean
40  integer, allocatable, dimension(:,:) :: ensemble_pelist_atmos
41  integer, allocatable, dimension(:,:) :: ensemble_pelist_land
42  integer, allocatable, dimension(:,:) :: ensemble_pelist_ice
43  integer, allocatable, dimension(:) :: ensemble_pelist_ocean_filter
44  integer, allocatable, dimension(:) :: ensemble_pelist_atmos_filter
45  integer, allocatable, dimension(:) :: ensemble_pelist_land_filter
46  integer, allocatable, dimension(:) :: ensemble_pelist_ice_filter
47 
48  integer :: ensemble_size = 1
49  integer :: ensemble_id = 1
51  integer :: land_npes_pm=0,ice_npes_pm=0
52 
54  public :: ensemble_pelist_setup
56 contains
57 
58 !> \brief ensemble_manager_init
59 !!
60 !! \throw FATAL, "ensemble_manager_mod: ensemble_nml variable ensemble_size must be a positive integer"
61 !! \throw FATAL, "ensemble_manager_mod: ensemble_nml variable ensemble_size should be no larger than MAX_ENSEMBLE_SIZE, change ensemble_size or increase MAX_ENSEMBLE_SIZE"
62 !! \throw FATAL, "ensemble_size must be divis by npes"
63 !! \throw FATAL, "get_ensemble_pelist: size of pelist 1st index < ensemble_size"
64 !! \throw FATAL, "get_ensemble_pelist: size of pelist 2nd index < ocean_npes_pm"
65 !! \throw FATAL, "get_ensemble_pelist: size of pelist 2nd index < atmos_npes_pm"
66 !! \throw FATAL, "get_ensemble_pelist: size of pelist 2nd index < land_npes_pm"
67 !! \throw FATAL, "get_ensemble_pelist: size of pelist 2nd index < ice_npes_pm"
68 !! \throw FATAL, "get_ensemble_pelist: unknown argument name=[name]"
69 !! \throw FATAL, "get_ensemble_pelist: size of pelist 2nd index < total_npes_pm"
70  subroutine ensemble_manager_init()
71 
72 
73  integer :: i, io_status, ioun, npes, ierr
74 
75  namelist /ensemble_nml/ ensemble_size
76 
77 #ifdef INTERNAL_FILE_NML
78  read (input_nml_file, ensemble_nml, iostat=io_status)
79 #else
80  ioun = open_namelist_file()
81  read(ioun,nml=ensemble_nml,iostat = io_status)
82  call close_file(ioun)
83 #endif
84  ierr = check_nml_error(io_status, 'ensemble_nml')
85 
86  if(ensemble_size < 1) call mpp_error(fatal, &
87  'ensemble_manager_mod: ensemble_nml variable ensemble_size must be a positive integer')
88  if(ensemble_size > max_ensemble_size) call mpp_error(fatal, &
89  'ensemble_manager_mod: ensemble_nml variable ensemble_size should be no larger than MAX_ENSEMBLE_SIZE, '// &
90  'change ensemble_size or increase MAX_ENSEMBLE_SIZE')
91 
92  pe = mpp_pe()
93  npes = mpp_npes()
94  if (npes < ensemble_size) then
95  call mpp_error(fatal,'npes must be >= ensemble_size')
96  endif
98  if (mod(npes, total_npes_pm) /= 0) call mpp_error(fatal,'ensemble_size must be divis by npes')
99 
100  call mpp_declare_pelist((/(i,i=0,npes-1)/),'_ens0') ! for ensemble driver
101 
102  end subroutine ensemble_manager_init
103 
104  function get_ensemble_id()
105  integer :: get_ensemble_id
107  end function get_ensemble_id
108 
109  function get_ensemble_size()
111  integer, dimension(6) :: get_ensemble_size
112 
119 
120  end function get_ensemble_size
121 
122 
123  subroutine get_ensemble_pelist(pelist, name)
125  integer, intent(inout) :: pelist(:,:)
126  character(len=*), intent(in), optional :: name
127 
128  if (size(pelist,1) < ensemble_size) &
129  call mpp_error(fatal,'get_ensemble_pelist: size of pelist 1st index < ensemble_size')
130 
131  if(present(name)) then
132  select case(name)
133  case('ocean')
134  if (size(pelist,2) < ocean_npes_pm)&
135  call mpp_error(fatal,'get_ensemble_pelist: size of pelist 2nd index < ocean_npes_pm')
136  pelist = 0
137  pelist(1:ensemble_size,1:ocean_npes_pm) = &
139 
140  case('atmos')
141  if (size(pelist,2) < atmos_npes_pm)&
142  call mpp_error(fatal,'get_ensemble_pelist: size of pelist 2nd index < atmos_npes_pm')
143  pelist = 0
144  pelist(1:ensemble_size,1:atmos_npes_pm) = &
146 
147  case('land')
148  if (size(pelist,2) < land_npes_pm)&
149  call mpp_error(fatal,'get_ensemble_pelist: size of pelist 2nd index < land_npes_pm')
150  pelist = 0
151  pelist(1:ensemble_size,1:land_npes_pm) = &
153 
154  case('ice')
155  if (size(pelist,2) < ice_npes_pm)&
156  call mpp_error(fatal,'get_ensemble_pelist: size of pelist 2nd index < ice_npes_pm')
157  pelist = 0
158  pelist(1:ensemble_size,1:ice_npes_pm) = &
160 
161  case default
162  call mpp_error(fatal,'get_ensemble_pelist: unknown argument name='//name)
163  end select
164  else
165  if (size(pelist,2) < total_npes_pm)&
166  call mpp_error(fatal,'get_ensemble_pelist: size of pelist 2nd index < total_npes_pm')
167  pelist = 0
168  pelist(1:ensemble_size,1:total_npes_pm) = &
170  endif
171 
172  return
173  end subroutine get_ensemble_pelist
174 
175 !> \brief get_ensemble_filter_pelist
176 !!
177 !! \throw FATAL, "get_ensemble_filter_pelist: size of pelist argument < ensemble_size * ocean_npes_pm"
178 !! \throw FATAL, "get_ensemble_filter_pelist: size of pelist argument < ensemble_size * atmos_npes_pm"
179 !! \throw FATAL, "get_ensemble_filter_pelist: size of pelist argument < ensemble_size * land_npes_pm"
180 !! \throw FATAL, "get_ensemble_filter_pelist: size of pelist argument < ensemble_size * ice_npes_pm"
181 !! \throw FATAL, "get_ensemble_filter_pelist: unknown argument name=[name]"
182  subroutine get_ensemble_filter_pelist(pelist, name)
184  integer, intent(inout) :: pelist(:)
185  character(len=*), intent(in) :: name
186 
187  select case(name)
188  case('ocean')
189  if (size(pelist) < ensemble_size * ocean_npes_pm)&
190  call mpp_error(fatal,'get_ensemble_filter_pelist: size of pelist argument < ensemble_size * ocean_npes_pm')
191  pelist = 0
192  pelist(1:ensemble_size*ocean_npes_pm) = &
194 
195  case('atmos')
196  if (size(pelist) < ensemble_size * atmos_npes_pm)&
197  call mpp_error(fatal,'get_ensemble_filter_pelist: size of pelist argument < ensemble_size * atmos_npes_pm')
198  pelist = 0
199  pelist(1:ensemble_size*atmos_npes_pm) = &
201 
202  case('land')
203  if (size(pelist) < ensemble_size * land_npes_pm)&
204  call mpp_error(fatal,'get_ensemble_filter_pelist: size of pelist argument < ensemble_size * land_npes_pm')
205  pelist = 0
206  pelist(1:ensemble_size*land_npes_pm) = &
208 
209  case('ice')
210  if (size(pelist) < ensemble_size * ice_npes_pm)&
211  call mpp_error(fatal,'get_ensemble_filter_pelist: size of pelist argument < ensemble_size * ice_npes_pm')
212  pelist = 0
213  pelist(1:ensemble_size*ice_npes_pm) = &
215 
216  case default
217  call mpp_error(fatal,'get_ensemble_filter_pelist: unknown argument name='//name)
218  end select
219 
220 
221  return
222  end subroutine get_ensemble_filter_pelist
223 
224 !nnz: I think the following block of code should be contained in a subroutine
225 ! to consolidate and ensure the consistency of declaring the various pelists.
226 !>\brief ensemble_pelist_setup
227 !!
228 !! \throw FATAL, "ensemble_manager_mod: land_npes > atmos_npes"
229 !! \throw FATAL, "ensemble_manager_mod: ice_npes > atmos_npes"
230  subroutine ensemble_pelist_setup(concurrent, atmos_npes, ocean_npes, land_npes, ice_npes, &
231  Atm_pelist, Ocean_pelist, Land_pelist, Ice_pelist)
232  logical, intent(in) :: concurrent
233  integer, intent(in) :: atmos_npes, ocean_npes
234  integer, intent(in) :: land_npes, ice_npes
235  integer, dimension(:), intent(inout) :: atm_pelist, ocean_pelist
236  integer, dimension(:), intent(inout) :: land_pelist, ice_pelist
237  integer :: atmos_pe_start, atmos_pe_end, ocean_pe_start, ocean_pe_end
238  integer :: land_pe_start, land_pe_end, ice_pe_start, ice_pe_end
239  character(len=10) :: pelist_name, text
240  integer :: npes, n, m ,i
241 
242  npes = total_npes_pm
243 
244  ! make sure land_npes and ice_npes are not greater than atmos_npes
245  if(land_npes > atmos_npes) call mpp_error(fatal, 'ensemble_manager_mod: land_npes > atmos_npes')
246  if(ice_npes > atmos_npes) call mpp_error(fatal, 'ensemble_manager_mod: ice_npes > atmos_npes')
247 
249  allocate(ensemble_pelist_ocean(1:ensemble_size, 1:ocean_npes) )
250  allocate(ensemble_pelist_atmos(1:ensemble_size, 1:atmos_npes) )
251  allocate(ensemble_pelist_land(1:ensemble_size, 1:land_npes) )
252  allocate(ensemble_pelist_ice(1:ensemble_size, 1:ice_npes) )
253 
254  atmos_pe_start = 0
255  ocean_pe_start = 0
256  land_pe_start = 0
257  ice_pe_start = 0
258  if( concurrent .OR. atmos_npes+ocean_npes == npes )then
259  ocean_pe_start = ensemble_size*atmos_npes
260  endif
261  do n=1,ensemble_size
262  atmos_pe_end = atmos_pe_start + atmos_npes - 1
263  ocean_pe_end = ocean_pe_start + ocean_npes - 1
264  land_pe_end = land_pe_start + land_npes - 1
265  ice_pe_end = ice_pe_start + ice_npes - 1
266  ensemble_pelist_atmos(n, 1:atmos_npes) = (/(i,i=atmos_pe_start,atmos_pe_end)/)
267  ensemble_pelist_ocean(n, 1:ocean_npes) = (/(i,i=ocean_pe_start,ocean_pe_end)/)
268  ensemble_pelist_land(n, 1:land_npes) = (/(i,i=land_pe_start, land_pe_end)/)
269  ensemble_pelist_ice(n, 1:ice_npes) = (/(i,i=ice_pe_start, ice_pe_end)/)
270  ensemble_pelist(n, 1:atmos_npes) = ensemble_pelist_atmos(n, 1:atmos_npes)
271  if( concurrent .OR. atmos_npes+ocean_npes == npes ) &
272  ensemble_pelist(n, atmos_npes+1:npes) = ensemble_pelist_ocean(n, 1:ocean_npes)
273  if(any(ensemble_pelist(n,:) == pe)) ensemble_id = n
274  write(pelist_name,'(a,i2.2)') '_ens',n
275  call mpp_declare_pelist(ensemble_pelist(n,:), trim(pelist_name))
276  atmos_pe_start = atmos_pe_end + 1
277  ocean_pe_start = ocean_pe_end + 1
278  land_pe_start = atmos_pe_start
279  ice_pe_start = atmos_pe_start
280  enddo
281 
282  atm_pelist(:) = ensemble_pelist_atmos(ensemble_id,:)
283  ocean_pelist(:) = ensemble_pelist_ocean(ensemble_id,:)
284  land_pelist(:) = ensemble_pelist_land(ensemble_id,:)
285  ice_pelist(:) = ensemble_pelist_ice(ensemble_id,:)
286 
287  ! write(pelist_name,'(a,i2.2)') '_ocn_ens',ensemble_id
288  ! call mpp_declare_pelist(Ocean%pelist , trim(pelist_name) )
289 
290  ! write(pelist_name,'(a,i2.2)') '_atm_ens',ensemble_id
291  ! call mpp_declare_pelist(Atm%pelist , trim(pelist_name) )
292  !
293  !nnz: The above is sufficient for non-concurrent mode.
294  ! BUT
295  ! For atmosphere_init to work in ensemble, concurrent mode
296  ! the following Atm_pelist should be declared (per ensemble member)
297  ! instead of the above Atm%pelist!
298  !
299  ! allocate( Atm_pelist(1:ensemble_size, 1:atmos_npes) )
300  ! do n=1,ensemble_size
301  ! do i=1, atmos_npes
302  ! Atm_pelist(n, i) = ensemble_pelist(n, i)
303  ! enddo
304  ! write(pelist_name,'(a,i2.2)') '_atm_ens',n
305  ! call mpp_declare_pelist(Atm_pelist(n,:) , trim(pelist_name) )
306  ! enddo
307  !
308  ! The way I understand this with the help of Totalview is:
309  ! With mpp_declare_pelist(Atm%pelist)
310  ! When we are in fv_arrays_init when mp_init(comID) is called
311  ! comID is the same for the atmospheric PE's for both ensemble members
312  ! since peset(5)%id is the same (7) for those PE's, so the PE count is double what it should be inside
313  ! mp_init().
314  ! It is also true that for Ocean PE's, peset(4)%id is the same (6) for Ocean PE's in both ensemble members
315  ! but for Ocean it is not a problem because Ocean is not trying to create new communicators
316  ! from this peset whereas ATM does (vis mp_init).
317  !
318  ! Who sets peset(i)%id ? Can it be modified to assign different %id for the two subsets.
319  ! peset(i)%id = 0 for Ocean PE's on ATM pesets and for ATM PE's on Ocean pesets.
320  !
321  ! With mpp_declare_pelist(Atm_pelist(n,:)) n=1,...,ensemble_size
322  ! we get separate pesets for each ATM ensemble member and each with a different %id and mp_init is cured.
323  !
324  ! There is also a matter of precedence. If we have both calls
325  ! call mpp_declare_pelist(Atm%pelist , trim(pelist_name) )
326  ! and
327  ! call mpp_declare_pelist(Atm_pelist(n,:) , trim(pelist_name) )
328  ! then concurrent run fails because with call mpp_set_current_pelist( Atm%pelist )
329  ! peset(i) is searched for i=1,2,... and the first pelist that matches argument, its peset is set as current.
330  !
331  ! To be consistent with ATM and OCEAN we can do the following
332  ! (eventhough mpp_declare_pelist(Ocean%pelist) is adequate right now.)
333 
334  if( concurrent )then
335  do n=1,ensemble_size
336  write(pelist_name,'(a,i2.2)') 'atm_ens',n
337  call mpp_declare_pelist(ensemble_pelist_atmos(n,:) , trim(pelist_name) )
338  write(pelist_name,'(a,i2.2)') 'ocn_ens',n
339  call mpp_declare_pelist(ensemble_pelist_ocean(n,:) , trim(pelist_name) )
340  write(pelist_name,'(a,i2.2)') 'lnd_ens',n
341  call mpp_declare_pelist(ensemble_pelist_land(n,:) , trim(pelist_name) )
342  write(pelist_name,'(a,i2.2)') 'ice_ens',n
343  call mpp_declare_pelist(ensemble_pelist_ice(n,:) , trim(pelist_name) )
344  enddo
345  else
346  write(pelist_name,'(a,i2.2)') 'atm_ens',ensemble_id
347  call mpp_declare_pelist(atm_pelist , trim(pelist_name) )
348  write(pelist_name,'(a,i2.2)') 'ocn_ens',ensemble_id
349  call mpp_declare_pelist(ocean_pelist , trim(pelist_name) )
350  write(pelist_name,'(a,i2.2)') 'lnd_ens',ensemble_id
351  call mpp_declare_pelist(land_pelist , trim(pelist_name) )
352  write(pelist_name,'(a,i2.2)') 'ice_ens',ensemble_id
353  call mpp_declare_pelist(ice_pelist , trim(pelist_name) )
354  endif
355 
356  ocean_npes_pm = ocean_npes
357  atmos_npes_pm = atmos_npes
358  land_npes_pm = land_npes
359  ice_npes_pm = ice_npes
360 
361  !Declare pelist of all Ocean, Atmos, Land and Ice pes across all ensembles ( filters )
366  do n=1,ensemble_size
367  do m=1,ocean_npes_pm
368  i=(n-1)*ocean_npes_pm + m
370  enddo
371  do m=1,atmos_npes_pm
372  i=(n-1)*atmos_npes_pm + m
374  enddo
375  do m=1,land_npes_pm
376  i=(n-1)*land_npes_pm + m
378  enddo
379  do m=1,ice_npes_pm
380  i=(n-1)*ice_npes_pm + m
382  enddo
383  enddo
384 
385  write(pelist_name,'(a)') 'ocn_filter'
386  call mpp_declare_pelist(ensemble_pelist_ocean_filter, trim(pelist_name) )
387 
388  write(pelist_name,'(a)') 'atm_filter'
389  call mpp_declare_pelist(ensemble_pelist_atmos_filter, trim(pelist_name) )
390 
391  write(pelist_name,'(a)') 'lnd_filter'
392  call mpp_declare_pelist(ensemble_pelist_land_filter, trim(pelist_name) )
393 
394  write(pelist_name,'(a)') 'ice_filter'
395  call mpp_declare_pelist(ensemble_pelist_ice_filter, trim(pelist_name) )
396 
397  !
398  !Rename output files to identify the ensemble
399  !If ensemble_size=1 do not rename files so that the same coupler
400  !can be used for non-ensemble experiments
401  !
402  if (ensemble_size > 1) then
403  write( text,'(a,i2.2)' ) 'ens_', ensemble_id
404  !Append ensemble_id to the restart filenames
405  call set_filename_appendix(trim(text))
406  endif
407 
408  end subroutine ensemble_pelist_setup
409 
410 
411 end module ensemble_manager_mod
Definition: fms.F90:20
integer, parameter max_ensemble_size
integer, dimension(:), allocatable ensemble_pelist_ice_filter
integer, dimension(:,:), allocatable ensemble_pelist
Definition: mpp.F90:39
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
subroutine, public get_ensemble_pelist(pelist, name)
subroutine, public set_filename_appendix(string_in)
Definition: fms_io.F90:8366
integer, dimension(:), allocatable ensemble_pelist_atmos_filter
subroutine, public get_ensemble_filter_pelist(pelist, name)
get_ensemble_filter_pelist
integer function, dimension(6), public get_ensemble_size()
integer, dimension(:,:), allocatable ensemble_pelist_ocean
integer, dimension(:), allocatable ensemble_pelist_ocean_filter
ensemble_manager_mod
integer, dimension(:,:), allocatable ensemble_pelist_atmos
integer, dimension(:,:), allocatable ensemble_pelist_land
integer, dimension(:), allocatable ensemble_pelist_land_filter
subroutine, public ensemble_manager_init()
ensemble_manager_init
integer function, public get_ensemble_id()
subroutine, public ensemble_pelist_setup(concurrent, atmos_npes, ocean_npes, land_npes, ice_npes, Atm_pelist, Ocean_pelist, Land_pelist, Ice_pelist)
ensemble_pelist_setup
integer, dimension(:,:), allocatable ensemble_pelist_ice