1module ensembleStateVector_mod
2 ! MODULE ensembleStateVector_mod (prefix='ens' category='6. High-level data objects')
3 !
4 !:Purpose: Store and manipulate ensemble of state vectors and the ensemble
5 ! mean.
6 !
7 use ramDisk_mod
8 use midasMpi_mod
9 use fileNames_mod
10 use gridStateVector_mod
11 use gridStateVectorFileIO_mod
12 use interpolation_mod
13 use horizontalCoord_mod
14 use verticalCoord_mod
15 use lamAnalysisGridTransforms_mod
16 use oceanMask_mod
17 use timeCoord_mod
18 use utilities_mod
19 use varNameList_mod
20 use codePrecision_mod
21 implicit none
22 save
23 private
24
25 ! public procedures
26 public :: struct_ens, ens_isAllocated, ens_allocate, ens_deallocate, ens_zero
27 public :: ens_readEnsemble, ens_writeEnsemble, ens_copy, ens_copy4Dto3D, ens_add
28 public :: ens_getOneLevMean_r8, ens_modifyVarName
29 public :: ens_varExist, ens_getNumLev, ens_getNumMembers, ens_getNumSubEns
30 public :: ens_computeMean, ens_removeMean, ens_removeGlobalMean, ens_recenter
31 public :: ens_copyEnsMean, ens_copyToEnsMean, ens_copyMember, ens_insertMember
32 public :: ens_computeStdDev, ens_copyEnsStdDev, ens_normalize
33 public :: ens_getMask, ens_copyMaskToGsv
34 public :: ens_getOneLev_r4, ens_getOneLev_r8
35 public :: ens_getOffsetFromVarName, ens_getLevFromK, ens_getVarNameFromK
36 public :: ens_getNumK, ens_getKFromLevVarName, ens_getDataKind, ens_getPathName
37 public :: ens_getVco, ens_getHco, ens_getLatLonBounds, ens_getNumStep
38 public :: ens_varNamesList, ens_applyMaskLAM
39
40 integer,external :: get_max_rss
41
42 type :: struct_oneLev_r4
43 real(4), pointer :: onelevel(:,:,:,:) => null()
44 end type struct_oneLev_r4
45
46 type :: struct_oneLev_r8
47 real(8), pointer :: onelevel(:,:,:,:) => null()
48 end type struct_oneLev_r8
49
50 type :: struct_ens
51 private
52 logical :: allocated = .false.
53 integer :: numMembers
54 integer :: dataKind = 4 ! default value
55 integer :: fileMemberIndex1 = 1 ! first member number in ensemble set
56 type(struct_gsv) :: statevector_work
57 type(struct_hco), pointer :: hco_core
58 type(struct_oneLev_r8), allocatable :: allLev_ensMean_r8(:), allLev_ensStdDev_r8(:)
59 type(struct_oneLev_r4), allocatable :: allLev_r4(:)
60 type(struct_oneLev_r8), allocatable :: allLev_r8(:)
61 logical :: meanIsComputed = .false.
62 logical :: stdDevIsComputed = .false.
63 logical :: meanIsRemoved = .false.
64 integer, allocatable :: subEnsIndexList(:), nEnsSubEns(:)
65 integer :: numSubEns
66 character(len=256) :: enspathname
67 character(len=12) :: hInterpolateDegree='UNSPECIFIED' ! 'LINEAR' or 'CUBIC' or 'NEAREST'
68 end type struct_ens
69
70CONTAINS
71
72 !--------------------------------------------------------------------------
73 ! ens_isAllocated
74 !--------------------------------------------------------------------------
75 function ens_isAllocated(ens) result(isAllocated)
76 !
77 !:Purpose: Return true if object has been allocated
78 !
79 implicit none
80
81 ! Arguments:
82 type(struct_ens), intent(in) :: ens
83 ! Result:
84 logical :: isAllocated
85
86 isAllocated = ens%allocated
87 end function ens_isAllocated
88
89 !--------------------------------------------------------------------------
90 ! ens_allocate
91 !--------------------------------------------------------------------------
92 subroutine ens_allocate(ens, numMembers, numStep, hco_comp, vco_ens, &
93 dateStampList, hco_core_opt, varNames_opt, dataKind_opt, &
94 hInterpolateDegree_opt, fileMemberIndex1_opt)
95 !
96 !:Purpose: Allocate an ensembleStateVector object
97 !
98 implicit none
99
100 ! Arguments:
101 type(struct_ens), intent(inout) :: ens
102 integer, intent(in) :: numMembers
103 integer, intent(in) :: numStep
104 type(struct_hco), pointer, intent(in) :: hco_comp
105 type(struct_hco), pointer, optional, intent(in) :: hco_core_opt
106 type(struct_vco), pointer, intent(in) :: vco_ens
107 integer, intent(in) :: dateStampList(:)
108 character(len=*), optional, intent(in) :: varNames_opt(:)
109 integer, optional, intent(in) :: dataKind_opt
110 integer, optional, intent(in) :: fileMemberIndex1_opt
111 character(len=*), optional, intent(in) :: hInterpolateDegree_opt
112
113 ! Locals:
114 integer :: varLevIndex, lon1, lon2, lat1, lat2, k1, k2
115 character(len=4), pointer :: varNames(:)
116
117 if ( ens%allocated ) then
118 write(*,*) 'ens_allocate: this object is already allocated, deallocating first.'
119 call ens_deallocate( ens )
120 end if
121
122 if ( present(dataKind_opt) ) ens%dataKind = dataKind_opt
123
124 if ( present(fileMemberIndex1_opt) ) ens%fileMemberIndex1 = fileMemberIndex1_opt
125
126 if ( present(hInterpolateDegree_opt) ) then
127 ! set the horizontal interpolation degree
128 ens%hInterpolateDegree = trim(hInterpolateDegree_opt)
129 else
130 ens%hInterpolateDegree = 'LINEAR' ! default, for legacy purposes
131 end if
132
133 nullify(varNames)
134 if (present(varNames_opt)) then
135 allocate(varNames(size(varNames_opt)))
136 varNames(:) = varNames_opt(:)
137 else
138 call gsv_varNamesList(varNames)
139 end if
140
141 call gsv_allocate( ens%statevector_work, &
142 numStep, hco_comp, vco_ens, &
143 datestamplist_opt=dateStampList, mpi_local_opt=.true., &
144 varNames_opt=varNames, dataKind_opt=ens%dataKind, &
145 hInterpolateDegree_opt = hInterpolateDegree_opt)
146
147 lon1 = ens%statevector_work%myLonBeg
148 lon2 = ens%statevector_work%myLonEnd
149 lat1 = ens%statevector_work%myLatBeg
150 lat2 = ens%statevector_work%myLatEnd
151 k1 = ens%statevector_work%mykBeg
152 k2 = ens%statevector_work%mykEnd
153
154 if (ens%dataKind == 8) then
155 allocate( ens%allLev_r8(k1:k2) )
156 do varLevIndex = k1, k2
157 allocate( ens%allLev_r8(varLevIndex)%onelevel(numMembers,numStep,lon1:lon2,lat1:lat2) )
158 end do
159 else if (ens%dataKind == 4) then
160 allocate( ens%allLev_r4(k1:k2) )
161 do varLevIndex = k1, k2
162 allocate( ens%allLev_r4(varLevIndex)%onelevel(numMembers,numStep,lon1:lon2,lat1:lat2) )
163 end do
164 else
165 call utl_abort('ens_allocate: unknown value of datakind')
166 end if
167
168 ens%allocated = .true.
169 ens%numMembers = numMembers
170 if (present(hco_core_opt)) then
171 ens%hco_core => hco_core_opt
172 else
173 ens%hco_core => hco_comp
174 end if
175
176 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
177
178 end subroutine ens_allocate
179
180 !--------------------------------------------------------------------------
181 ! ens_allocateMean
182 !--------------------------------------------------------------------------
183 subroutine ens_allocateMean(ens)
184 !
185 !:Purpose: Allocate the ensemble mean arrays within an ensembleStateVector object
186 !
187 implicit none
188
189 ! Arguments:
190 type(struct_ens), intent(inout) :: ens
191
192 ! Locals:
193 integer :: lon1, lon2, lat1, lat2, k1, k2, varLevIndex, numStep
194
195 lon1 = ens%statevector_work%myLonBeg
196 lon2 = ens%statevector_work%myLonEnd
197 lat1 = ens%statevector_work%myLatBeg
198 lat2 = ens%statevector_work%myLatEnd
199 k1 = ens%statevector_work%mykBeg
200 k2 = ens%statevector_work%mykEnd
201 numStep = ens%statevector_work%numStep
202
203 allocate( ens%allLev_ensMean_r8(k1:k2) )
204 do varLevIndex = k1, k2
205 allocate( ens%allLev_ensMean_r8(varLevIndex)%onelevel(ens%numSubEns,numStep,lon1:lon2,lat1:lat2) )
206 ens%allLev_ensMean_r8(varLevIndex)%onelevel(:,:,:,:) = 0.0d0
207 end do
208
209 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
210
211 end subroutine ens_allocateMean
212
213 !--------------------------------------------------------------------------
214 ! ens_allocateStdDev
215 !--------------------------------------------------------------------------
216 subroutine ens_allocateStdDev(ens)
217 !
218 !:Purpose: Allocate the ensemble stddev arrays within an ensembleStateVector object
219 !
220 implicit none
221
222 ! Arguments:
223 type(struct_ens), intent(inout) :: ens
224
225 ! Locals:
226 integer :: lon1, lon2, lat1, lat2, k1, k2, varLevIndex, numStep
227
228 lon1 = ens%statevector_work%myLonBeg
229 lon2 = ens%statevector_work%myLonEnd
230 lat1 = ens%statevector_work%myLatBeg
231 lat2 = ens%statevector_work%myLatEnd
232 k1 = ens%statevector_work%mykBeg
233 k2 = ens%statevector_work%mykEnd
234 numStep = ens%statevector_work%numStep
235
236 allocate( ens%allLev_ensStdDev_r8(k1:k2) )
237 do varLevIndex = k1, k2
238 allocate( ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,numStep,lon1:lon2,lat1:lat2) )
239 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(:,:,:,:) = 0.0d0
240 end do
241
242 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
243
244 end subroutine ens_allocateStdDev
245
246 !--------------------------------------------------------------------------
247 ! ens_deallocate
248 !--------------------------------------------------------------------------
249 subroutine ens_deallocate( ens )
250 !
251 !:Purpose: Deallocate an ensembleStateVector object
252 !
253 implicit none
254
255 ! Arguments:
256 type(struct_ens), intent(inout) :: ens
257
258 ! Locals:
259 integer :: k1, k2, varLevIndex
260
261 if ( .not. ens%allocated ) return
262
263 k1 = ens%statevector_work%mykBeg
264 k2 = ens%statevector_work%mykEnd
265
266 if (ens%dataKind == 8) then
267 do varLevIndex = k1, k2
268 deallocate( ens%allLev_r8(varLevIndex)%onelevel )
269 end do
270 deallocate( ens%allLev_r8 )
271 else if (ens%dataKind == 4) then
272 do varLevIndex = k1, k2
273 deallocate( ens%allLev_r4(varLevIndex)%onelevel )
274 end do
275 deallocate( ens%allLev_r4 )
276 end if
277
278 if (ens%stdDevIsComputed) then
279 do varLevIndex = k1, k2
280 deallocate( ens%allLev_ensStdDev_r8(varLevIndex)%onelevel )
281 end do
282 deallocate( ens%allLev_ensStdDev_r8 )
283 end if
284
285 if (ens%meanIsComputed) then
286 do varLevIndex = k1, k2
287 deallocate( ens%allLev_ensMean_r8(varLevIndex)%onelevel )
288 end do
289 deallocate( ens%allLev_ensMean_r8 )
290 deallocate( ens%subEnsIndexList )
291 deallocate( ens%nEnsSubEns )
292 end if
293
294 ens%allocated = .false.
295
296 end subroutine ens_deallocate
297
298 !--------------------------------------------------------------------------
299 ! ens_modifyVarName
300 !--------------------------------------------------------------------------
301 subroutine ens_modifyVarName(ens, oldVarName, newVarName)
302 !
303 !:Purpose: Change an existing variable name within the ensemble.
304 ! This is only used when the contents of a variable are
305 ! transformed into another variable **in place**.
306 !
307 implicit none
308
309 ! Arguments:
310 type(struct_ens), intent(inout) :: ens
311 character(len=*), intent(in) :: oldVarName
312 character(len=*), intent(in) :: newVarName
313
314 call gsv_modifyVarName(ens%statevector_work,oldVarName, newVarName)
315
316 end subroutine ens_modifyVarName
317
318 !--------------------------------------------------------------------------
319 ! ens_copy
320 !--------------------------------------------------------------------------
321 subroutine ens_copy(ens_in,ens_out)
322 !
323 !:Purpose: Copy the contents of one ensembleStateVector object into another
324 !
325 implicit none
326
327 ! Arguments:
328 type(struct_ens), intent(in) :: ens_in
329 type(struct_ens), intent(inout) :: ens_out
330
331 ! Locals:
332 integer :: lon1, lon2, lat1, lat2, k1, k2
333 integer :: varLevIndex, stepIndex, latIndex, lonIndex, memberIndex
334
335 if (.not.ens_in%allocated) then
336 call utl_abort('ens_copy: ens_in not yet allocated')
337 end if
338 if (.not.ens_out%allocated) then
339 call utl_abort('ens_copy: ens_out not yet allocated')
340 end if
341
342 call gsv_copyMask(ens_in%statevector_work,ens_out%statevector_work)
343
344 lon1 = ens_out%statevector_work%myLonBeg
345 lon2 = ens_out%statevector_work%myLonEnd
346 lat1 = ens_out%statevector_work%myLatBeg
347 lat2 = ens_out%statevector_work%myLatEnd
348 k1 = ens_out%statevector_work%mykBeg
349 k2 = ens_out%statevector_work%mykEnd
350
351 if ( ens_out%dataKind == 8 .and. ens_in%dataKind == 8 ) then
352
353 !$OMP PARALLEL DO PRIVATE (varLevIndex,stepIndex,latIndex,lonIndex,memberIndex)
354 do varLevIndex = k1, k2
355 do latIndex = lat1, lat2
356 do lonIndex = lon1, lon2
357 do stepIndex = 1, ens_out%statevector_work%numStep
358 do memberIndex = 1, ens_out%numMembers
359 ens_out%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
360 ens_in %allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex)
361 end do
362 end do
363 end do
364 end do
365 end do
366 !$OMP END PARALLEL DO
367
368 else if ( ens_out%dataKind == 4 .and. ens_in%dataKind == 4 ) then
369
370 !$OMP PARALLEL DO PRIVATE (varLevIndex,stepIndex,latIndex,lonIndex,memberIndex)
371 do varLevIndex = k1, k2
372 do latIndex = lat1, lat2
373 do lonIndex = lon1, lon2
374 do stepIndex = 1, ens_out%statevector_work%numStep
375 do memberIndex = 1, ens_out%numMembers
376 ens_out%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
377 ens_in %allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex)
378 end do
379 end do
380 end do
381 end do
382 end do
383 !$OMP END PARALLEL DO
384
385 else
386 call utl_abort('ens_copy: Data type must be the same for both ensembleStatevectors')
387 end if
388
389 end subroutine ens_copy
390
391 !--------------------------------------------------------------------------
392 ! ens_copy4Dto3D
393 !--------------------------------------------------------------------------
394 subroutine ens_copy4Dto3D(ens_in,ens_out)
395 !
396 !:Purpose: Copy contents of a 4D ensemble into a 3D ensemble object by
397 ! extracting the middle time step.
398 !
399 implicit none
400
401 ! Arguments:
402 type(struct_ens), intent(in) :: ens_in
403 type(struct_ens), intent(inout) :: ens_out
404
405 ! Locals:
406 integer :: lon1, lon2, lat1, lat2, k1, k2
407 integer :: varLevIndex, latIndex, lonIndex, memberIndex
408 integer :: numStepIn, numStepOut, middleStepIndex
409
410 if (.not.ens_in%allocated) then
411 call utl_abort('ens_copy4Dto3D: ens_in not yet allocated')
412 end if
413 if (.not.ens_out%allocated) then
414 call utl_abort('ens_copy4Dto3D: ens_out not yet allocated')
415 end if
416
417 call gsv_copyMask(ens_in%statevector_work,ens_out%statevector_work)
418
419 lon1 = ens_out%statevector_work%myLonBeg
420 lon2 = ens_out%statevector_work%myLonEnd
421 lat1 = ens_out%statevector_work%myLatBeg
422 lat2 = ens_out%statevector_work%myLatEnd
423 k1 = ens_out%statevector_work%mykBeg
424 k2 = ens_out%statevector_work%mykEnd
425 numStepIn = ens_in%statevector_work%numStep
426 numStepOut = ens_out%statevector_work%numStep
427
428 if (numStepOut /= 1) call utl_abort('ens_copy4Dto3D: output ensemble must have only 1 timestep')
429 if (numStepIn == 1) then
430 write(*,*) 'ens_copy4Dto3D: WARNING: input ensemble only has 1 timestep, will simply copy.'
431 end if
432 middleStepIndex = (numStepIn + 1) / 2
433
434 if ( ens_out%dataKind == 8 .and. ens_in%dataKind == 8 ) then
435
436 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,memberIndex)
437 do varLevIndex = k1, k2
438 do latIndex = lat1, lat2
439 do lonIndex = lon1, lon2
440 do memberIndex = 1, ens_out%numMembers
441 ens_out%allLev_r8(varLevIndex)%onelevel(memberIndex,1,lonIndex,latIndex) = &
442 ens_in %allLev_r8(varLevIndex)%onelevel(memberIndex,middleStepIndex,lonIndex,latIndex)
443 end do
444 end do
445 end do
446 end do
447 !$OMP END PARALLEL DO
448
449 else if ( ens_out%dataKind == 4 .and. ens_in%dataKind == 4 ) then
450
451 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,memberIndex)
452 do varLevIndex = k1, k2
453 do latIndex = lat1, lat2
454 do lonIndex = lon1, lon2
455 do memberIndex = 1, ens_out%numMembers
456 ens_out%allLev_r4(varLevIndex)%onelevel(memberIndex,1,lonIndex,latIndex) = &
457 ens_in %allLev_r4(varLevIndex)%onelevel(memberIndex,middleStepIndex,lonIndex,latIndex)
458 end do
459 end do
460 end do
461 end do
462 !$OMP END PARALLEL DO
463
464 else
465 call utl_abort('ens_copy4Dto3D: Data type must be the same for both ensembleStatevectors')
466 end if
467
468 end subroutine ens_copy4Dto3D
469
470 !--------------------------------------------------------------------------
471 ! ens_add
472 !--------------------------------------------------------------------------
473 subroutine ens_add(ens_in, ens_inOut, scaleFactorIn_opt, scaleFactorInOut_opt)
474 !
475 !:Purpose: Add the contents of the ens_in ensemble to the ens_inOut ensemble.
476 !
477 implicit none
478
479 ! arguments
480 type(struct_ens), intent(in) :: ens_in
481 type(struct_ens), intent(inout) :: ens_inOut
482 real(8), optional, intent(in) :: scaleFactorIn_opt
483 real(8), optional, intent(in) :: scaleFactorInOut_opt
484
485 ! locals
486 integer :: lon1, lon2, lat1, lat2, k1, k2
487 integer :: varLevIndex, stepIndex, latIndex, lonIndex, memberIndex
488 real(4) :: scaleFactorIn_r4, scaleFactorInOut_r4
489 real(8) :: scaleFactorIn, scaleFactorInOut
490
491 if (.not.ens_in%allocated) then
492 call utl_abort('ens_add: ens_in not yet allocated')
493 end if
494 if (.not.ens_inOut%allocated) then
495 call utl_abort('ens_add: ens_inOut not yet allocated')
496 end if
497
498 lon1 = ens_inOut%statevector_work%myLonBeg
499 lon2 = ens_inOut%statevector_work%myLonEnd
500 lat1 = ens_inOut%statevector_work%myLatBeg
501 lat2 = ens_inOut%statevector_work%myLatEnd
502 k1 = ens_inOut%statevector_work%mykBeg
503 k2 = ens_inOut%statevector_work%mykEnd
504
505 if ( ens_inOut%dataKind == 8 .and. ens_in%dataKind == 8 ) then
506
507 if (present(scaleFactorIn_opt)) then
508 scaleFactorIn = scaleFactorIn_opt
509 else
510 scaleFactorIn = 1.0d0
511 end if
512 if (present(scaleFactorInOut_opt)) then
513 scaleFactorInOut = scaleFactorInOut_opt
514 else
515 scaleFactorInOut = 1.0d0
516 end if
517
518 !$OMP PARALLEL DO PRIVATE (varLevIndex,stepIndex,latIndex,lonIndex,memberIndex)
519 do varLevIndex = k1, k2
520 do latIndex = lat1, lat2
521 do lonIndex = lon1, lon2
522 do stepIndex = 1, ens_inOut%statevector_work%numStep
523 do memberIndex = 1, ens_inOut%numMembers
524 ens_inOut%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
525 scaleFactorInOut * &
526 ens_inOut%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) + &
527 scaleFactorIn * &
528 ens_in%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex)
529 end do
530 end do
531 end do
532 end do
533 end do
534 !$OMP END PARALLEL DO
535
536 else if ( ens_inOut%dataKind == 4 .and. ens_in%dataKind == 4 ) then
537
538 if (present(scaleFactorIn_opt)) then
539 scaleFactorIn_r4 = real(scaleFactorIn_opt,4)
540 else
541 scaleFactorIn_r4 = 1.0
542 end if
543 if (present(scaleFactorInOut_opt)) then
544 scaleFactorInOut_r4 = real(scaleFactorInOut_opt,4)
545 else
546 scaleFactorInOut_r4 = 1.0
547 end if
548
549 !$OMP PARALLEL DO PRIVATE (varLevIndex,stepIndex,latIndex,lonIndex,memberIndex)
550 do varLevIndex = k1, k2
551 do latIndex = lat1, lat2
552 do lonIndex = lon1, lon2
553 do stepIndex = 1, ens_inOut%statevector_work%numStep
554 do memberIndex = 1, ens_inOut%numMembers
555 ens_inOut%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
556 scaleFactorInOut_r4 * &
557 ens_inOut%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) + &
558 scaleFactorIn_r4 * &
559 ens_in%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex)
560 end do
561 end do
562 end do
563 end do
564 end do
565 !$OMP END PARALLEL DO
566
567 else
568 call utl_abort('ens_add: Data type must be the same for both ensembleStatevectors')
569 end if
570
571 end subroutine ens_add
572
573 !--------------------------------------------------------------------------
574 ! ens_zero
575 !--------------------------------------------------------------------------
576 subroutine ens_zero(ens)
577 !
578 !:Purpose: Set the main contents of an ensembleStateVector object to zero
579 !
580 implicit none
581
582 ! Arguments:
583 type(struct_ens), intent(inout) :: ens
584
585 ! Locals:
586 integer :: lon1, lon2, lat1, lat2, k1, k2
587 integer :: varLevIndex, stepIndex, latIndex, lonIndex, memberIndex
588
589 if (.not.ens%allocated) then
590 call utl_abort('ens_zero: ens not yet allocated')
591 end if
592
593 lon1 = ens%statevector_work%myLonBeg
594 lon2 = ens%statevector_work%myLonEnd
595 lat1 = ens%statevector_work%myLatBeg
596 lat2 = ens%statevector_work%myLatEnd
597 k1 = ens%statevector_work%mykBeg
598 k2 = ens%statevector_work%mykEnd
599
600 if ( ens%dataKind == 8 ) then
601
602 !$OMP PARALLEL DO PRIVATE (varLevIndex,stepIndex,latIndex,lonIndex,memberIndex)
603 do varLevIndex = k1, k2
604 do latIndex = lat1, lat2
605 do lonIndex = lon1, lon2
606 do stepIndex = 1, ens%statevector_work%numStep
607 do memberIndex = 1, ens%numMembers
608 ens%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = 0.d0
609 end do
610 end do
611 end do
612 end do
613 end do
614 !$OMP END PARALLEL DO
615
616 else if ( ens%dataKind == 4 ) then
617
618 !$OMP PARALLEL DO PRIVATE (varLevIndex,stepIndex,latIndex,lonIndex,memberIndex)
619 do varLevIndex = k1, k2
620 do latIndex = lat1, lat2
621 do lonIndex = lon1, lon2
622 do stepIndex = 1, ens%statevector_work%numStep
623 do memberIndex = 1, ens%numMembers
624 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = 0.0
625 end do
626 end do
627 end do
628 end do
629 end do
630 !$OMP END PARALLEL DO
631
632 end if
633
634 end subroutine ens_zero
635
636 !--------------------------------------------------------------------------
637 ! ens_copyToStateWork (private routine)
638 !--------------------------------------------------------------------------
639 subroutine ens_copyToStateWork(ens, dataType, memberIndex_opt, &
640 subEnsIndex_opt)
641 !
642 !:Purpose: Copy the selected contents of an ensembleStateVector into
643 ! the 'work' stateVector within the object. The possible
644 ! types of content are: 'member', 'mean', or 'stdDev'.
645 !
646 implicit none
647
648 ! Arguments:
649 type(struct_ens), intent(inout) :: ens
650 character(len=*), intent(in) :: dataType
651 integer, optional, intent(in) :: memberIndex_opt
652 integer, optional, intent(in) :: subEnsIndex_opt
653
654 ! Locals:
655 real(4), pointer :: ptr4d_r4(:,:,:,:)
656 real(8), pointer :: ptr4d_r8(:,:,:,:)
657 integer :: k1, k2, varLevIndex, numStep, stepIndex
658 integer :: memberIndex, subEnsIndex
659
660 k1 = ens%statevector_work%mykBeg
661 k2 = ens%statevector_work%mykEnd
662 numStep = ens%statevector_work%numStep
663
664 select case(trim(dataType))
665 case ('member')
666 if (present(memberIndex_opt)) then
667 memberIndex = memberIndex_opt
668 else
669 call utl_abort('ens_copyToStateWork: memberIndex_opt must be provided with dataType=member')
670 end if
671 case ('mean','stdDev')
672 if (present(subEnsIndex_opt)) then
673 subEnsIndex = subEnsIndex_opt
674 else
675 subEnsIndex = 1
676 end if
677 case default
678 write(*,*)
679 write(*,*) 'Unsupported dataType: ', trim(dataType)
680 write(*,*) ' please select either: member, mean or stdDev'
681 call utl_abort('ens_copyToStateWork')
682 end select
683
684 if (ens%dataKind == 8) then
685 call gsv_getField(ens%statevector_work,ptr4d_r8)
686 do stepIndex = 1, numStep
687 do varLevIndex = k1, k2
688 if (dataType == 'member') then
689 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
690 ens%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,:,:)
691 else if (dataType == 'mean') then
692 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
693 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:)
694 else if (dataType == 'stdDev') then
695 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
696 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:)
697 end if
698 end do
699 end do
700 else if (ens%dataKind == 4) then
701 call gsv_getField(ens%statevector_work,ptr4d_r4)
702 do stepIndex = 1, numStep
703 do varLevIndex = k1, k2
704 if (dataType == 'member') then
705 ptr4d_r4(:,:,varLevIndex,stepIndex) = &
706 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,:,:)
707 else if (dataType == 'mean') then
708 ptr4d_r4(:,:,varLevIndex,stepIndex) = &
709 real(ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:),4)
710 else if (dataType == 'stdDev') then
711 ptr4d_r4(:,:,varLevIndex,stepIndex) = &
712 real(ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:),4)
713 end if
714 end do
715 end do
716 end if
717
718 end subroutine ens_copyToStateWork
719
720 !--------------------------------------------------------------------------
721 ! ens_copyFromStateWork
722 !--------------------------------------------------------------------------
723 subroutine ens_copyFromStateWork(ens, dataType, memberIndex_opt, &
724 subEnsIndex_opt)
725 !
726 !:Purpose: This is the inverse operation as ens_copyToStateWork.
727 !
728 implicit none
729
730 ! Arguments:
731 type(struct_ens), intent(inout) :: ens
732 character(len=*), intent(in) :: dataType
733 integer, optional, intent(in) :: memberIndex_opt
734 integer, optional, intent(in) :: subEnsIndex_opt
735
736 ! Locals:
737 real(4), pointer :: ptr4d_r4(:,:,:,:)
738 real(8), pointer :: ptr4d_r8(:,:,:,:)
739 integer :: k1, k2, varLevIndex, numStep, stepIndex
740 integer :: memberIndex, subEnsIndex
741
742 k1 = ens%statevector_work%mykBeg
743 k2 = ens%statevector_work%mykEnd
744 numStep = ens%statevector_work%numStep
745
746 select case(trim(dataType))
747 case ('member')
748 if (present(memberIndex_opt)) then
749 memberIndex = memberIndex_opt
750 else
751 call utl_abort('ens_copyFromStateWork: memberIndex_opt must be provided with dataType=member')
752 end if
753 case ('mean','stdDev')
754 if (present(subEnsIndex_opt)) then
755 subEnsIndex = subEnsIndex_opt
756 else
757 subEnsIndex = 1
758 end if
759 case default
760 write(*,*)
761 write(*,*) 'Unsupported dataType: ', trim(dataType)
762 write(*,*) ' please select either: member, mean or stdDev'
763 call utl_abort('ens_copyToStateWork')
764 end select
765
766 if (ens%dataKind == 8) then
767 call gsv_getField(ens%statevector_work,ptr4d_r8)
768 do stepIndex = 1, numStep
769 do varLevIndex = k1, k2
770 if (dataType == 'member') then
771 ens%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
772 ptr4d_r8(:,:,varLevIndex,stepIndex)
773 else if (dataType == 'mean') then
774 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:) = &
775 ptr4d_r8(:,:,varLevIndex,stepIndex)
776 else if (dataType == 'stdDev') then
777 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:) = &
778 ptr4d_r8(:,:,varLevIndex,stepIndex)
779 end if
780 end do
781 end do
782 else if (ens%dataKind == 4) then
783 call gsv_getField(ens%statevector_work,ptr4d_r4)
784 do stepIndex = 1, numStep
785 do varLevIndex = k1, k2
786 if (dataType == 'member') then
787 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
788 ptr4d_r4(:,:,varLevIndex,stepIndex)
789 else if (dataType == 'mean') then
790 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:) = &
791 real(ptr4d_r4(:,:,varLevIndex,stepIndex),8)
792 else if (dataType == 'stdDev') then
793 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:) = &
794 real(ptr4d_r4(:,:,varLevIndex,stepIndex),8)
795 end if
796 end do
797 end do
798 end if
799
800 end subroutine ens_copyFromStateWork
801
802 !--------------------------------------------------------------------------
803 ! ens_getOneLev_r4
804 !--------------------------------------------------------------------------
805 function ens_getOneLev_r4(ens,kIndex) result(oneLevLevel)
806 !
807 !:Purpose: Return a 4D pointer to a single level of a real4 ensemble. The
808 ! dimensions of the pointer are:
809 ! (memberIndex, stepIndex, lonIndex, latIndex)
810 !
811 implicit none
812
813 ! Arguments:
814 type(struct_ens), intent(inout) :: ens
815 integer, intent(in) :: kIndex
816 ! Result:
817 real(4), pointer :: oneLevLevel(:,:,:,:)
818
819 ! Locals:
820 integer :: lon1, lat1
821
822 lon1 = ens%statevector_work%myLonBeg
823 lat1 = ens%statevector_work%myLatBeg
824
825 oneLevLevel(1:,1:,lon1:,lat1:) => ens%allLev_r4(kIndex)%onelevel(:,:,:,:)
826
827 end function ens_getOneLev_r4
828
829 !--------------------------------------------------------------------------
830 ! ens_getOneLev_r8
831 !--------------------------------------------------------------------------
832 function ens_getOneLev_r8(ens,kIndex) result(oneLevLevel)
833 !
834 !:Purpose: Return a 4D pointer to a single level of a real8 ensemble. The
835 ! dimensions of the pointer are:
836 ! (memberIndex, stepIndex, lonIndex, latIndex)
837 !
838 implicit none
839
840 ! Arguments:
841 type(struct_ens), intent(in) :: ens
842 integer , intent(in) :: kIndex
843 ! Result:
844 real(8), pointer :: oneLevLevel(:,:,:,:)
845
846 ! Locals:
847 integer :: lon1, lat1
848
849 lon1 = ens%statevector_work%myLonBeg
850 lat1 = ens%statevector_work%myLatBeg
851
852 oneLevLevel(1:,1:,lon1:,lat1:) => ens%allLev_r8(kIndex)%onelevel(:,:,:,:)
853
854 end function ens_getOneLev_r8
855
856 !--------------------------------------------------------------------------
857 ! ens_getOneLevMean_r8
858 !--------------------------------------------------------------------------
859 function ens_getOneLevMean_r8(ens,subEnsIndex,kIndex) result(field)
860 !
861 !:Purpose: Return a 3D pointer to a single level the ensemble mean. The
862 ! dimensions of the pointer are:
863 ! (stepIndex, lonIndex, latIndex)
864 !
865 implicit none
866
867 ! Arguments:
868 type(struct_ens), intent(inout) :: ens
869 integer, intent(in) :: subEnsIndex, kIndex
870 ! Result:
871 real(8), pointer :: field(:,:,:)
872
873 ! Locals:
874 integer :: lon1, lat1
875
876 lon1 = ens%statevector_work%myLonBeg
877 lat1 = ens%statevector_work%myLatBeg
878
879 field(1:, lon1:, lat1:) => ens%allLev_ensMean_r8(kIndex)%onelevel(subEnsIndex,:,:,:)
880
881 end function ens_getOneLevMean_r8
882
883 !--------------------------------------------------------------------------
884 ! ens_copyEnsMean
885 !--------------------------------------------------------------------------
886 subroutine ens_copyEnsMean(ens, statevector, subEnsIndex_opt)
887 !
888 !:Purpose: Copy the ensemble mean into the supplied stateVector.
889 !
890 implicit none
891
892 ! Arguments:
893 type(struct_ens), intent(inout) :: ens
894 type(struct_gsv), intent(inout) :: statevector
895 integer, optional, intent(in) :: subEnsIndex_opt
896
897 ! Locals:
898 real(8), pointer :: ptr4d_r8(:,:,:,:)
899 real(4), pointer :: ptr4d_r4(:,:,:,:)
900 integer :: k1, k2, varLevIndex, stepIndex, numStep, subEnsIndex
901 character(len=4), pointer :: varNamesInEns(:)
902
903 if( present(subEnsIndex_opt) ) then
904 subEnsIndex = subEnsIndex_opt
905 else
906 subEnsIndex = 1
907 end if
908
909 k1 = ens%statevector_work%mykBeg
910 k2 = ens%statevector_work%mykEnd
911 numStep = ens%statevector_work%numStep
912
913 if (.not. gsv_isAllocated(statevector)) then
914 nullify(varNamesInEns)
915 call gsv_varNamesList(varNamesInEns,ens%statevector_work)
916 call gsv_allocate(statevector, numStep, &
917 ens%statevector_work%hco, ens%statevector_work%vco, &
918 varNames_opt=varNamesInEns, datestamp_opt=tim_getDatestamp(), &
919 mpi_local_opt=.true., dataKind_opt=8 )
920 deallocate(varNamesInEns)
921 end if
922
923 statevector%onPhysicsGrid(:) = ens%statevector_work%onPhysicsGrid
924 statevector%hco_physics => ens%statevector_work%hco_physics
925
926 if (statevector%dataKind == 8) then
927 call gsv_getField(statevector,ptr4d_r8)
928 do stepIndex = 1, numStep
929 do varLevIndex = k1, k2
930 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
931 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:)
932 end do
933 end do
934 else
935 call gsv_getField(statevector,ptr4d_r4)
936 do stepIndex = 1, numStep
937 do varLevIndex = k1, k2
938 ptr4d_r4(:,:,varLevIndex,stepIndex) = &
939 real(ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:),4)
940 end do
941 end do
942 end if
943
944 end subroutine ens_copyEnsMean
945
946 !--------------------------------------------------------------------------
947 ! ens_copyToEnsMean
948 !--------------------------------------------------------------------------
949 subroutine ens_copyToEnsMean(ens, statevector, subEnsIndex_opt)
950 !
951 !:Purpose: Copy the supplied stateVector into the ensemble mean.
952 !
953 implicit none
954
955 ! Arguments:
956 type(struct_ens), intent(inout) :: ens
957 type(struct_gsv), intent(inout) :: statevector
958 integer, optional, intent(in) :: subEnsIndex_opt
959
960 ! Locals:
961 real(8), pointer :: ptr4d_r8(:,:,:,:)
962 real(4), pointer :: ptr4d_r4(:,:,:,:)
963 integer :: k1, k2, varLevIndex, stepIndex, numStep, subEnsIndex
964
965 if( present(subEnsIndex_opt) ) then
966 subEnsIndex = subEnsIndex_opt
967 else
968 subEnsIndex = 1
969 end if
970
971 k1 = ens%statevector_work%mykBeg
972 k2 = ens%statevector_work%mykEnd
973 numStep = ens%statevector_work%numStep
974
975 if (.not. gsv_isAllocated(statevector)) then
976 call utl_abort('ens_copyToEnsMean: supplied stateVector must be allocated')
977 end if
978
979 if (.not. allocated(ens%allLev_ensMean_r8)) then
980 call ens_allocateMean(ens)
981 else
982 do varLevIndex = k1, k2
983 ens%allLev_ensMean_r8(varLevIndex)%onelevel(:,:,:,:) = 0.0d0
984 end do
985 end if
986 ens%meanIsComputed = .true.
987
988 if (statevector%dataKind == 8) then
989 call gsv_getField(statevector,ptr4d_r8)
990 do stepIndex = 1, numStep
991 do varLevIndex = k1, k2
992 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:) = &
993 ptr4d_r8(:,:,varLevIndex,stepIndex)
994 end do
995 end do
996 else
997 call gsv_getField(statevector,ptr4d_r4)
998 do stepIndex = 1, numStep
999 do varLevIndex = k1, k2
1000 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,:,:) = &
1001 real(ptr4d_r4(:,:,varLevIndex,stepIndex),8)
1002 end do
1003 end do
1004 end if
1005
1006 end subroutine ens_copyToEnsMean
1007
1008 !--------------------------------------------------------------------------
1009 ! ens_copyEnsStdDev
1010 !--------------------------------------------------------------------------
1011 subroutine ens_copyEnsStdDev(ens, statevector)
1012 !
1013 !:Purpose: Copy the ensemble StdDev into the supplied stateVector.
1014 !
1015 implicit none
1016
1017 ! Arguments:
1018 type(struct_ens), intent(inout) :: ens
1019 type(struct_gsv), intent(inout) :: statevector
1020
1021 ! Locals:
1022 real(8), pointer :: ptr4d_r8(:,:,:,:)
1023 real(4), pointer :: ptr4d_r4(:,:,:,:)
1024 integer :: k1, k2, varLevIndex, stepIndex, numStep
1025 character(len=4), pointer :: varNamesInEns(:)
1026
1027 k1 = ens%statevector_work%mykBeg
1028 k2 = ens%statevector_work%mykEnd
1029 numStep = ens%statevector_work%numStep
1030
1031 if (.not. gsv_isAllocated(statevector)) then
1032 nullify(varNamesInEns)
1033 call gsv_varNamesList(varNamesInEns,ens%statevector_work)
1034 call gsv_allocate(statevector, numStep, &
1035 ens%statevector_work%hco, ens%statevector_work%vco, &
1036 varNames_opt=varNamesInEns, datestamp_opt=tim_getDatestamp(), &
1037 mpi_local_opt=.true., dataKind_opt=8 )
1038 deallocate(varNamesInEns)
1039 end if
1040
1041 if (statevector%dataKind == 8) then
1042 call gsv_getField(statevector,ptr4d_r8)
1043 do stepIndex = 1, numStep
1044 do varLevIndex = k1, k2
1045 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
1046 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,:,:)
1047 end do
1048 end do
1049 else
1050 call gsv_getField(statevector,ptr4d_r4)
1051 do stepIndex = 1, numStep
1052 do varLevIndex = k1, k2
1053 ptr4d_r4(:,:,varLevIndex,stepIndex) = &
1054 real(ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,:,:),4)
1055 end do
1056 end do
1057 end if
1058
1059 end subroutine ens_copyEnsStdDev
1060
1061 !--------------------------------------------------------------------------
1062 ! ens_copyMember
1063 !--------------------------------------------------------------------------
1064 subroutine ens_copyMember(ens, statevector, memberIndex)
1065 !
1066 !:Purpose: Copy a selected ensemble member into the supplied stateVector.
1067 !
1068 implicit none
1069
1070 ! Arguments:
1071 type(struct_ens), intent(in) :: ens
1072 type(struct_gsv), intent(inout) :: statevector
1073 integer, intent(in) :: memberIndex
1074
1075 ! Locals:
1076 real(8), pointer :: ptr4d_r8(:,:,:,:)
1077 real(4), pointer :: ptr4d_r4(:,:,:,:)
1078 integer :: k1, k2, varLevIndex, stepIndex, numStep, varIndex
1079 integer :: gsvLevIndex, ensVarLevIndex, nLev
1080 character(len=4), pointer :: varNamesInEns(:)
1081 character(len=4), pointer :: varNamesInGsv(:)
1082 character(len=4) :: varName
1083 logical :: sameVariables
1084
1085 numStep = ens%statevector_work%numStep
1086
1087 nullify(varNamesInEns)
1088 call gsv_varNamesList(varNamesInEns, ens%statevector_work)
1089
1090 if (.not. gsv_isAllocated(statevector)) then
1091 call utl_abort('ens_copyMember: statevector not allocated')
1092 else
1093 nullify(varNamesInGsv)
1094 call gsv_varNamesList(varNamesInGsv, statevector)
1095 end if
1096
1097 sameVariables = .false.
1098 if (size(ens%statevector_work%varExistlist) == size(statevector%varExistlist)) then
1099 if (all(ens%statevector_work%varExistlist == statevector%varExistlist)) then
1100 sameVariables = .true.
1101 end if
1102 end if
1103
1104 if (sameVariables) then
1105
1106 k1 = ens%statevector_work%mykBeg
1107 k2 = ens%statevector_work%mykEnd
1108
1109 if (ens%dataKind == 8) then
1110 call gsv_getField(statevector,ptr4d_r8)
1111 do stepIndex = 1, numStep
1112 do varLevIndex = k1, k2
1113 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
1114 ens%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,:,:)
1115 end do
1116 end do
1117 else if (ens%dataKind == 4) then
1118 if (gsv_getDataKind(statevector) == 8) then
1119 call gsv_getField(statevector,ptr4d_r8)
1120 do stepIndex = 1, numStep
1121 do varLevIndex = k1, k2
1122 ptr4d_r8(:,:,varLevIndex,stepIndex) = &
1123 real(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,:,:),8)
1124 end do
1125 end do
1126 else
1127 call gsv_getField(statevector,ptr4d_r4)
1128 do stepIndex = 1, numStep
1129 do varLevIndex = k1, k2
1130 ptr4d_r4(:,:,varLevIndex,stepIndex) = &
1131 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,:,:)
1132 end do
1133 end do
1134 end if
1135 end if
1136
1137 else
1138
1139 do varIndex = 1, size(varNamesInGsv)
1140 varName = varNamesInGsv(varIndex)
1141 if (.not. ens_varExist(ens,varName)) cycle
1142 nLev = gsv_getNumLev(statevector,vnl_varLevelFromVarname(varName),varName)
1143 if (ens%dataKind == 8) then
1144 call gsv_getField(statevector,ptr4d_r8,varName_opt=varName)
1145 do stepIndex = 1, numStep
1146 do gsvLevIndex = 1, nLev
1147 ensVarLevIndex = gsvLevIndex + ens_getOffsetFromVarName(ens,varName)
1148 ptr4d_r8(:,:,gsvLevIndex,stepIndex) = &
1149 ens%allLev_r8(ensVarLevIndex)%onelevel(memberIndex,stepIndex,:,:)
1150 end do
1151 end do
1152 else if (ens%dataKind == 4) then
1153 if (gsv_getDataKind(statevector) == 8) then
1154 call gsv_getField(statevector,ptr4d_r8,varName_opt=varName)
1155 do stepIndex = 1, numStep
1156 do gsvLevIndex = 1, nLev
1157 ensVarLevIndex = gsvLevIndex + ens_getOffsetFromVarName(ens,varName)
1158 ptr4d_r8(:,:,gsvLevIndex,stepIndex) = &
1159 real(ens%allLev_r4(ensVarLevIndex)%onelevel(memberIndex,stepIndex,:,:),8)
1160 end do
1161 end do
1162 else
1163 call gsv_getField(statevector,ptr4d_r4,varName_opt=varName)
1164 do stepIndex = 1, numStep
1165 do gsvLevIndex = 1, nLev
1166 ensVarLevIndex = gsvLevIndex + ens_getOffsetFromVarName(ens,varName)
1167 ptr4d_r4(:,:,gsvLevIndex,stepIndex) = &
1168 ens%allLev_r4(ensVarLevIndex)%onelevel(memberIndex,stepIndex,:,:)
1169 end do
1170 end do
1171 end if
1172 end if
1173 end do
1174
1175 end if
1176
1177 if (associated(varNamesInGsv)) deallocate(varNamesInGsv)
1178 if (associated(varNamesInEns)) deallocate(varNamesInEns)
1179
1180 end subroutine ens_copyMember
1181
1182 !--------------------------------------------------------------------------
1183 ! ens_insertMember
1184 !--------------------------------------------------------------------------
1185 subroutine ens_insertMember(ens, statevector, memberIndex)
1186 !
1187 !:Purpose: Copy the supplied stateVector in the selected ensemble member.
1188 !
1189 implicit none
1190
1191 ! Arguments:
1192 type(struct_ens), intent(inout) :: ens
1193 type(struct_gsv), intent(inout) :: statevector
1194 integer, intent(in) :: memberIndex
1195
1196 ! Locals:
1197 real(4), pointer :: ptr4d_r4(:,:,:,:)
1198 real(8), pointer :: ptr4d_r8(:,:,:,:)
1199 integer :: k1, k2, varLevIndex, stepIndex, numStep, varIndex
1200 integer :: gsvLevIndex, ensVarLevIndex, nLev
1201 character(len=4), pointer :: varNamesInEns(:)
1202 character(len=4), pointer :: varNamesInGsv(:)
1203 character(len=4) :: varName
1204 logical :: sameVariables
1205
1206 if (.not. gsv_isAllocated(ens%statevector_work)) then
1207 call utl_abort('ens_insertMember: ens not allocated')
1208 end if
1209
1210 numStep = ens%statevector_work%numStep
1211
1212 nullify(varNamesInEns)
1213 call gsv_varNamesList(varNamesInEns, ens%statevector_work)
1214 nullify(varNamesInGsv)
1215 call gsv_varNamesList(varNamesInGsv, statevector)
1216
1217 sameVariables = .false.
1218 if (size(ens%statevector_work%varExistlist) == size(statevector%varExistlist)) then
1219 if (all(ens%statevector_work%varExistlist == statevector%varExistlist)) then
1220 sameVariables = .true.
1221 end if
1222 end if
1223
1224 if (sameVariables) then
1225
1226 k1 = ens%statevector_work%mykBeg
1227 k2 = ens%statevector_work%mykEnd
1228
1229 if (ens%dataKind == 8) then
1230 call gsv_getField(statevector,ptr4d_r8)
1231 do stepIndex = 1, numStep
1232 do varLevIndex = k1, k2
1233 ens%allLev_r8(varLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
1234 ptr4d_r8(:,:,varLevIndex,stepIndex)
1235 end do
1236 end do
1237 else if (ens%dataKind == 4) then
1238 if (gsv_getDataKind(statevector) == 8) then
1239 call gsv_getField(statevector,ptr4d_r8)
1240 do stepIndex = 1, numStep
1241 do varLevIndex = k1, k2
1242 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
1243 real(ptr4d_r8(:,:,varLevIndex,stepIndex),4)
1244 end do
1245 end do
1246 else
1247 call gsv_getField(statevector,ptr4d_r4)
1248 do stepIndex = 1, numStep
1249 do varLevIndex = k1, k2
1250 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
1251 ptr4d_r4(:,:,varLevIndex,stepIndex)
1252 end do
1253 end do
1254 end if
1255 end if
1256
1257 else
1258
1259 do varIndex = 1, size(varNamesInGsv)
1260 varName = varNamesInGsv(varIndex)
1261 nLev = gsv_getNumLev(statevector,vnl_varLevelFromVarname(varName),varName)
1262 if (ens%dataKind == 8) then
1263 call gsv_getField(statevector,ptr4d_r8,varName_opt=varName)
1264 do stepIndex = 1, numStep
1265 do gsvLevIndex = 1, nLev
1266 ensVarLevIndex = gsvLevIndex + ens_getOffsetFromVarName(ens,varName)
1267 ens%allLev_r8(ensVarLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
1268 ptr4d_r8(:,:,gsvLevIndex,stepIndex)
1269 end do
1270 end do
1271 else if (ens%dataKind == 4) then
1272 if (gsv_getDataKind(statevector) == 8) then
1273 call gsv_getField(statevector,ptr4d_r8,varName_opt=varName)
1274 do stepIndex = 1, numStep
1275 do gsvLevIndex = 1, nLev
1276 ensVarLevIndex = gsvLevIndex + ens_getOffsetFromVarName(ens,varName)
1277 ens%allLev_r4(ensVarLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
1278 real(ptr4d_r8(:,:,gsvLevIndex,stepIndex),4)
1279 end do
1280 end do
1281 else
1282 call gsv_getField(statevector,ptr4d_r4,varName_opt=varName)
1283 do stepIndex = 1, numStep
1284 do gsvLevIndex = 1, nLev
1285 ensVarLevIndex = gsvLevIndex + ens_getOffsetFromVarName(ens,varName)
1286 ens%allLev_r4(ensVarLevIndex)%onelevel(memberIndex,stepIndex,:,:) = &
1287 ptr4d_r4(:,:,gsvLevIndex,stepIndex)
1288 end do
1289 end do
1290 end if
1291 end if
1292 end do ! varIndex
1293
1294 end if
1295
1296 if (associated(varNamesInGsv)) deallocate(varNamesInGsv)
1297 if (associated(varNamesInEns)) deallocate(varNamesInEns)
1298
1299 end subroutine ens_insertMember
1300
1301 !--------------------------------------------------------------------------
1302 ! ens_getMask
1303 !--------------------------------------------------------------------------
1304 subroutine ens_getMask(ens,oceanMask)
1305 !
1306 !:Purpose: Copy the instance of oceanMask from inside the ens object
1307 ! to the supplied instance of oceanMask.
1308 !
1309 implicit none
1310
1311 ! Arguments:
1312 type(struct_ens), intent(inout) :: ens
1313 type(struct_ocm), intent(inout) :: oceanMask
1314
1315 call ocm_copyMask(ens%statevector_work%oceanMask,oceanMask)
1316
1317 end subroutine ens_getMask
1318
1319 !--------------------------------------------------------------------------
1320 ! ens_copyMaskToGsv
1321 !--------------------------------------------------------------------------
1322 subroutine ens_copyMaskToGsv(ens,statevector)
1323 !
1324 !:Purpose: Copy the instance of oceanMask from inside the ens object
1325 ! to the instance inside the supplied stateVector object.
1326 !
1327 implicit none
1328
1329 ! Arguments:
1330 type(struct_ens), intent(inout) :: ens
1331 type(struct_gsv), intent(inout) :: statevector
1332
1333 call gsv_copyMask(ens%statevector_work,statevector)
1334
1335 end subroutine ens_copyMaskToGsv
1336
1337 !--------------------------------------------------------------------------
1338 ! ens_varExist
1339 !--------------------------------------------------------------------------
1340 function ens_varExist(ens,varName) result(varExist)
1341 !
1342 !:Purpose: Return true if the specified variable name exists in the ensemble.
1343 !
1344 implicit none
1345
1346 ! Arguments:
1347 type(struct_ens), intent(in) :: ens
1348 character(len=*), intent(in) :: varName
1349 ! Result:
1350 logical :: varExist
1351
1352 varExist = gsv_varExist(ens%statevector_work, varName)
1353
1354 end function ens_varExist
1355
1356 !--------------------------------------------------------------------------
1357 ! ens_varNamesList
1358 !--------------------------------------------------------------------------
1359 subroutine ens_varNamesList(varNames,ens_opt)
1360 !
1361 !:Purpose: Return a list of the variable names that exist in the ensemble.
1362 !
1363 implicit none
1364
1365 ! Arguments:
1366 type(struct_ens), optional, intent(in) :: ens_opt
1367 character(len=4), pointer, intent(inout) :: varNames(:)
1368
1369 if (associated(varNames)) then
1370 call utl_abort('ens_varNamesList: varNames must be NULL pointer on input')
1371 end if
1372
1373 if (present(ens_opt)) then
1374 call gsv_varNamesList(varNames, ens_opt%statevector_work)
1375 else
1376 call gsv_varNamesList(varNames)
1377 end if
1378
1379 end subroutine ens_varNamesList
1380
1381 !--------------------------------------------------------------------------
1382 ! ens_getNumLev
1383 !--------------------------------------------------------------------------
1384 function ens_getNumLev(ens,varLevel,varName_opt) result(nlev)
1385 !
1386 !:Purpose: Return the number of vertical levels of the ensemble.
1387 !
1388 implicit none
1389
1390 ! Arguments:
1391 type(struct_ens), intent(in) :: ens
1392 character(len=*), intent(in) :: varLevel
1393 character(len=*), optional, intent(in) :: varName_opt
1394 ! Result:
1395 integer :: nlev
1396
1397 nlev = vco_getNumLev(ens%statevector_work%vco,varLevel,varName_opt)
1398
1399 end function ens_getNumLev
1400
1401 !--------------------------------------------------------------------------
1402 ! ens_getNumMembers
1403 !--------------------------------------------------------------------------
1404 function ens_getNumMembers(ens) result(numMembers)
1405 !
1406 !:Purpose: Return the number of members in the ensemble.
1407 !
1408 implicit none
1409
1410 ! Arguments:
1411 type(struct_ens), intent(in) :: ens
1412 ! Result:
1413 integer :: numMembers
1414
1415 numMembers = ens%numMembers
1416
1417 end function ens_getNumMembers
1418
1419
1420 !--------------------------------------------------------------------------
1421 ! ens_getNumSubEns
1422 !--------------------------------------------------------------------------
1423 function ens_getNumSubEns(ens) result(numMembers)
1424 !
1425 !:Purpose: Return the number of sub-ensembles in the ensemble.
1426 !
1427 implicit none
1428
1429 ! Arguments:
1430 type(struct_ens), intent(in) :: ens
1431 ! Result:
1432 integer :: numMembers
1433
1434 numMembers = ens%numSubEns
1435
1436 end function ens_getNumSubEns
1437
1438 !--------------------------------------------------------------------------
1439 ! ens_getNumK
1440 !--------------------------------------------------------------------------
1441 function ens_getNumK(ens) result(numK)
1442 !
1443 !:Purpose: Return the number of kIndex (a.k.a. varLevs) values of the ensemble.
1444 !
1445 implicit none
1446
1447 ! Arguments:
1448 type(struct_ens), intent(in) :: ens
1449 ! Result:
1450 integer :: numK
1451
1452 numK = 1 + ens%statevector_work%mykEnd - ens%statevector_work%mykBeg
1453
1454 end function ens_getNumK
1455
1456 !--------------------------------------------------------------------------
1457 ! ens_getDataKind
1458 !--------------------------------------------------------------------------
1459 function ens_getDataKind(ens) result(dataKind)
1460 !
1461 !:Purpose: Return the floating point kind of the ensemble (4 or 8).
1462 !
1463 implicit none
1464
1465 ! Arguments:
1466 type(struct_ens), intent(in) :: ens
1467 ! Result:
1468 integer :: dataKind
1469
1470 dataKind = ens%dataKind
1471
1472 end function ens_getDataKind
1473
1474 !--------------------------------------------------------------------------
1475 ! ens_getPathName
1476 !--------------------------------------------------------------------------
1477 function ens_getPathName(ens) result(pathName)
1478 !
1479 !:Purpose: Return the path name for the ensemble files.
1480 !
1481 implicit none
1482
1483 ! Arguments:
1484 type(struct_ens), intent(in) :: ens
1485 ! Result:
1486 character(len=256) :: pathName
1487
1488 pathName = ens%ensPathName
1489
1490 end function ens_getPathName
1491
1492 !--------------------------------------------------------------------------
1493 ! ens_getOffsetFromVarName
1494 !--------------------------------------------------------------------------
1495 function ens_getOffsetFromVarName(ens,varName) result(offset)
1496 !
1497 !:Purpose: Return the offset of the kIndex for the specified variable name.
1498 !
1499 implicit none
1500
1501 ! Arguments:
1502 type(struct_ens), intent(in) :: ens
1503 character(len=*), intent(in) :: varName
1504 ! Result:
1505 integer :: offset
1506
1507 if (.not. ens_varExist(ens,varName)) then
1508 call utl_abort('ens_getOffsetFromVarName: this varName is not present in ens: '//trim(varName))
1509 end if
1510
1511 offset=gsv_getOffsetFromVarName(ens%statevector_work,varName)
1512
1513 end function ens_getOffsetFromVarName
1514
1515 !--------------------------------------------------------------------------
1516 ! ens_getLevFromK
1517 !--------------------------------------------------------------------------
1518 function ens_getLevFromK(ens,kIndex) result(levIndex)
1519 !
1520 !:Purpose: Return the level index from the kIndex value.
1521 !
1522 implicit none
1523
1524 ! Arguments:
1525 type(struct_ens), intent(in) :: ens
1526 integer, intent(in) :: kIndex
1527 ! Result:
1528 integer :: levIndex
1529
1530 levIndex = gsv_getLevFromK(ens%statevector_work,kIndex)
1531
1532 end function ens_getLevFromK
1533
1534 !--------------------------------------------------------------------------
1535 ! ens_getKFromLevVarName
1536 !--------------------------------------------------------------------------
1537 function ens_getKFromLevVarName(ens, levIndex, varName) result(kIndex)
1538 !
1539 !:Purpose: Return the kIndex value for the specified level index
1540 ! and variable name.
1541 !
1542 implicit none
1543
1544 ! Arguments:
1545 type(struct_ens), intent(in) :: ens
1546 integer, intent(in) :: levIndex
1547 character(len=*), intent(in) :: varName
1548 ! Result:
1549 integer :: kIndex
1550
1551 kIndex = levIndex + gsv_getOffsetFromVarName(ens%statevector_work,trim(varName))
1552
1553 end function ens_getKFromLevVarName
1554
1555 !--------------------------------------------------------------------------
1556 ! ens_getVarNameFromK
1557 !--------------------------------------------------------------------------
1558 function ens_getVarNameFromK(ens,kIndex) result(varName)
1559 !
1560 !:Purpose: Return the variable name from the specified kIndex value.
1561 !
1562 implicit none
1563
1564 ! Arguments:
1565 type(struct_ens), intent(in) :: ens
1566 integer, intent(in) :: kIndex
1567 ! Result:
1568 character(len=4) :: varName
1569
1570 varName = gsv_getVarNameFromK(ens%statevector_work,kIndex)
1571
1572 end function ens_getVarNameFromK
1573
1574 !--------------------------------------------------------------------------
1575 ! ens_getVco
1576 !--------------------------------------------------------------------------
1577 function ens_getVco(ens) result(vco_ptr)
1578 !
1579 !:Purpose: Return a pointer to the verticalCoord object associate with the ensemble.
1580 !
1581 implicit none
1582
1583 ! Arguments:
1584 type(struct_ens), intent(in) :: ens
1585 ! Result:
1586 type(struct_vco), pointer :: vco_ptr
1587
1588 vco_ptr => ens%statevector_work%vco
1589
1590 end function ens_getVco
1591
1592 !--------------------------------------------------------------------------
1593 ! ens_getHco
1594 !--------------------------------------------------------------------------
1595 function ens_getHco(ens) result(hco_ptr)
1596 !
1597 !:Purpose: Return a pointer to the horizontalCoord object associate with the ensemble.
1598 !
1599 implicit none
1600
1601 ! Arguments:
1602 type(struct_ens), intent(in) :: ens
1603 ! Result:
1604 type(struct_hco), pointer :: hco_ptr
1605
1606 hco_ptr => ens%statevector_work%hco
1607
1608 end function ens_getHco
1609
1610 !--------------------------------------------------------------------------
1611 ! ens_getLatLonBounds
1612 !--------------------------------------------------------------------------
1613 subroutine ens_getLatLonBounds(ens, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
1614 !
1615 !:Purpose: Return the longitude and latitude index bounds for this mpi task.
1616 !
1617 implicit none
1618
1619 ! Arguments:
1620 type(struct_ens), intent(in) :: ens
1621 integer, intent(out) :: myLonBeg
1622 integer, intent(out) :: myLonEnd
1623 integer, intent(out) :: myLatBeg
1624 integer, intent(out) :: myLatEnd
1625
1626 myLonBeg = ens%statevector_work%myLonBeg
1627 myLonEnd = ens%statevector_work%myLonEnd
1628 myLatBeg = ens%statevector_work%myLatBeg
1629 myLatEnd = ens%statevector_work%myLatEnd
1630
1631 end subroutine ens_getLatLonBounds
1632
1633 !--------------------------------------------------------------------------
1634 ! ens_getNumStep
1635 !--------------------------------------------------------------------------
1636 function ens_getNumStep(ens) result(numStep)
1637 !
1638 !:Purpose: Return the number of time steps stored in the ensemble.
1639 !
1640 implicit none
1641
1642 ! Arguments:
1643 type(struct_ens), intent(in) :: ens
1644 ! Result:
1645 integer :: numStep
1646
1647 numStep = ens%statevector_work%numStep
1648
1649 end function ens_getNumStep
1650
1651 !--------------------------------------------------------------------------
1652 ! ens_computeMean
1653 !--------------------------------------------------------------------------
1654 subroutine ens_computeMean(ens, computeSubEnsMeans_opt, numSubEns_opt)
1655 !
1656 !:Purpose: Internally compute the ensemble mean.
1657 !
1658 implicit none
1659
1660 ! Arguments:
1661 type(struct_ens), intent(inout) :: ens
1662 logical, optional, intent(in) :: computeSubEnsMeans_opt
1663 integer, optional, intent(out) :: numSubEns_opt
1664
1665 ! Locals:
1666 logical :: computeSubEnsMeans, lExists
1667 character(len=256), parameter :: subEnsIndexFileName = 'subEnsembleIndex.txt'
1668 integer :: kulin, ierr, memberIndex, memberIndex2, stepIndex, subEnsIndex
1669 integer :: k1, k2, varLevIndex, lon1, lon2, lat1, lat2, numStep, lonIndex, latIndex
1670 integer :: fnom, fclos
1671
1672 if (present(computeSubEnsMeans_opt)) then
1673 computeSubEnsMeans = computeSubEnsMeans_opt
1674 else
1675 computeSubEnsMeans = .false.
1676 end if
1677
1678 ! Read sub-ensemble index list from file, if it exists
1679 if (.not. allocated(ens%subEnsIndexList)) then
1680 allocate(ens%subEnsIndexList(ens%numMembers))
1681 end if
1682 if ( computeSubEnsMeans ) then
1683 write(*,*) 'ens_computeMean: checking in ensemble directory if file with sub-ensemble index list exists: ',subEnsIndexFileName
1684 inquire(file=trim(ens%enspathname) // trim(subEnsIndexFileName),exist=lExists)
1685 if ( lExists ) then
1686 kulin = 0
1687 ierr = fnom(kulin,trim(ens%enspathname) // trim(subEnsIndexFileName),'FMT+SEQ+R/O',0)
1688 do memberIndex = 1, ens%numMembers
1689 read(kulin,*) memberIndex2, ens%subEnsIndexList(memberIndex)
1690 write(*,*) 'read from sub-ensemble index list: ',memberIndex, memberIndex2, ens%subEnsIndexList(memberIndex)
1691 end do
1692 ierr = fclos(kulin)
1693 else
1694 call utl_abort('ens_computeMean: could not find file with sub-ensemble index list')
1695 end if
1696 else
1697 ens%subEnsIndexList(:) = 1
1698 end if
1699 ens%numSubEns = maxval(ens%subEnsIndexList(:))
1700 if (.not. allocated(ens%nEnsSubEns)) then
1701 allocate(ens%nEnsSubEns(ens%numSubEns))
1702 end if
1703 ens%nEnsSubEns(:) = 0
1704 do memberIndex = 1, ens%numMembers
1705 ens%nEnsSubEns(ens%subEnsIndexList(memberIndex)) = ens%nEnsSubEns(ens%subEnsIndexList(memberIndex)) + 1
1706 end do
1707 write(*,*) 'ens_computeMean: number of sub-ensembles = ', ens%numSubEns
1708 write(*,*) 'ens_computeMean: number of members in each sub-ensemble = ', ens%nensSubEns(:)
1709
1710 lon1 = ens%statevector_work%myLonBeg
1711 lon2 = ens%statevector_work%myLonEnd
1712 lat1 = ens%statevector_work%myLatBeg
1713 lat2 = ens%statevector_work%myLatEnd
1714 k1 = ens%statevector_work%mykBeg
1715 k2 = ens%statevector_work%mykEnd
1716 numStep = ens%statevector_work%numStep
1717
1718 if (.not. allocated(ens%allLev_ensMean_r8)) then
1719 call ens_allocateMean(ens)
1720 else
1721 do varLevIndex = k1, k2
1722 ens%allLev_ensMean_r8(varLevIndex)%onelevel(:,:,:,:) = 0.0d0
1723 end do
1724 end if
1725 ens%meanIsComputed = .true.
1726
1727 ! Compute ensemble mean(s)
1728 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,stepIndex,memberIndex,subEnsIndex)
1729 do varLevIndex = k1, k2
1730 do latIndex = lat1, lat2
1731 do lonIndex = lon1, lon2
1732 do stepIndex = 1, ens%statevector_work%numStep
1733 do memberIndex = 1, ens%numMembers
1734 ens%allLev_ensMean_r8(varLevIndex)%onelevel(ens%subEnsIndexList(memberIndex),stepIndex,lonIndex,latIndex) = &
1735 ens%allLev_ensMean_r8(varLevIndex)%onelevel(ens%subEnsIndexList(memberIndex),stepIndex,lonIndex,latIndex) + &
1736 dble(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex))
1737 end do
1738 do subEnsIndex = 1, ens%numSubEns
1739 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,lonIndex,latIndex) = &
1740 ens%allLev_ensMean_r8(varLevIndex)%onelevel(subEnsIndex,stepIndex,lonIndex,latIndex) / &
1741 dble(ens%nEnsSubEns(subEnsIndex))
1742 end do
1743 end do
1744 end do
1745 end do
1746 end do
1747 !$OMP END PARALLEL DO
1748
1749 ! provide output argument value
1750 if ( present(numSubEns_opt) ) numSubEns_opt = ens%numSubEns
1751
1752 end subroutine ens_computeMean
1753
1754 !--------------------------------------------------------------------------
1755 ! ens_computeStdDev
1756 !--------------------------------------------------------------------------
1757 subroutine ens_computeStdDev(ens, containsScaledPerts_opt)
1758 !
1759 !:Purpose: Internally compute the ensemble stdDev.
1760 !
1761 implicit none
1762
1763 ! Arguments:
1764 type(struct_ens), intent(inout) :: ens
1765 logical, optional, intent(in) :: containsScaledPerts_opt
1766
1767 ! Locals:
1768 integer :: memberIndex, stepIndex, subEnsIndex
1769 integer :: k1, k2, varLevIndex, lon1, lon2, lat1, lat2, numStep, lonIndex, latIndex
1770 real(8), allocatable :: subEnsStdDev(:)
1771 logical :: containsScaledPerts
1772
1773 if ( present(containsScaledPerts_opt) ) then
1774 containsScaledPerts = containsScaledPerts_opt
1775 else
1776 containsScaledPerts = .false.
1777 if (.not.ens%meanIsRemoved .and. .not.ens%meanIsComputed) then
1778 if (mmpi_myid == 0) write(*,*) 'ens_computeStdDev: compute Mean since it was not already done'
1779 call ens_computeMean( ens )
1780 end if
1781 end if
1782
1783 ! Read sub-ensemble index list from file, if it exists
1784 ! The sub-ensembles should have been already read in routine 'ens_computeMean'
1785 write(*,*) 'ens_computeStdDev: number of sub-ensembles = ', ens%numSubEns
1786 write(*,*) 'ens_computeStdDev: number of members in each sub-ensemble = ', ens%nensSubEns(:)
1787
1788 lon1 = ens%statevector_work%myLonBeg
1789 lon2 = ens%statevector_work%myLonEnd
1790 lat1 = ens%statevector_work%myLatBeg
1791 lat2 = ens%statevector_work%myLatEnd
1792 k1 = ens%statevector_work%mykBeg
1793 k2 = ens%statevector_work%mykEnd
1794 numStep = ens%statevector_work%numStep
1795
1796 if (.not. allocated(ens%allLev_ensStdDev_r8)) then
1797 call ens_allocateStdDev(ens)
1798 else
1799 do varLevIndex = k1, k2
1800 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(:,:,:,:) = 0.0d0
1801 end do
1802 end if
1803 ens%StdDevIsComputed = .true.
1804
1805 if (containsScaledPerts) then
1806
1807 if (ens%numSubEns /= 1) then
1808 call utl_abort('ens_computeStdDev: sub-ensemble approach not compatible with scale perturbations')
1809 end if
1810
1811 ! Compute the ensemble StdDev from previously scale ensemble perturbations
1812 ! (i.e. pert = (fcst-mean)/(nEns-1) )
1813
1814 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,stepIndex,memberIndex)
1815 do varLevIndex = k1, k2
1816 do latIndex = lat1, lat2
1817 do lonIndex = lon1, lon2
1818 do stepIndex = 1, ens%statevector_work%numStep
1819
1820 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) = 0.d0
1821
1822 do memberIndex = 1, ens%numMembers
1823 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) = &
1824 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) + &
1825 dble(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex))**2
1826 end do
1827
1828 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) = &
1829 sqrt(ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex))
1830
1831 end do
1832 end do
1833 end do
1834 end do
1835 !$OMP END PARALLEL DO
1836
1837 else
1838
1839 allocate(subEnsStdDev(ens%numSubEns))
1840
1841 ! Compute global ensemble StdDev as the sqrt of the mean of each suchensemble variance
1842 ! var_subens(i) = sum( ( ens(j) - mean_subens(i) )**2, j=1..numEns_subens(i) ) / ( numEns_subens(i) - 1 )
1843 ! var_allensensemble = sum( numEns_subens(i) * var_subens(i), i=1..numSubEns)
1844 ! stddev = sqrt( var_allensensemble / numEnsTotal )
1845
1846 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,stepIndex,memberIndex,subEnsIndex,subEnsStdDev)
1847 do varLevIndex = k1, k2
1848 do latIndex = lat1, lat2
1849 do lonIndex = lon1, lon2
1850 do stepIndex = 1, ens%statevector_work%numStep
1851
1852 subEnsStdDev(:) = 0.0d0
1853
1854 if (ens%meanIsRemoved) then
1855 do memberIndex = 1, ens%numMembers
1856 subEnsStdDev(ens%subEnsIndexList(memberIndex)) = &
1857 subEnsStdDev(ens%subEnsIndexList(memberIndex)) + &
1858 (dble(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex)))**2
1859 end do
1860 else
1861 do memberIndex = 1, ens%numMembers
1862 subEnsStdDev(ens%subEnsIndexList(memberIndex)) = &
1863 subEnsStdDev(ens%subEnsIndexList(memberIndex)) + &
1864 (dble(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex)) - &
1865 ens%allLev_ensMean_r8(varLevIndex)%onelevel(ens%subEnsIndexList(memberIndex),stepIndex,lonIndex,latIndex))**2
1866 end do
1867 end if
1868
1869 do subEnsIndex = 1, ens%numSubEns
1870 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) = &
1871 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) + &
1872 ens%nEnsSubEns(subEnsIndex)*subEnsStdDev(subEnsIndex)/(ens%nEnsSubEns(subEnsIndex)-1)
1873
1874 end do
1875
1876 ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) = &
1877 sqrt( ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex) / dble(ens%numMembers) )
1878
1879 end do
1880 end do
1881 end do
1882 end do
1883 !$OMP END PARALLEL DO
1884
1885 deallocate(subEnsStdDev)
1886
1887 end if
1888
1889 end subroutine ens_computeStdDev
1890
1891 !--------------------------------------------------------------------------
1892 ! ens_normalize
1893 !--------------------------------------------------------------------------
1894 subroutine ens_normalize(ens)
1895 !
1896 !:Purpose: Normalize the ensemble by the 3D ensemble stdDev.
1897 !
1898 implicit none
1899
1900 ! Arguments:
1901 type(struct_ens), intent(inout) :: ens
1902
1903 ! Locals:
1904 integer :: lon1, lon2, lat1, lat2, k1, k2, numStep
1905 integer :: varLevIndex, latIndex, lonIndex, stepIndex, memberIndex
1906 real(8) :: factor
1907
1908 if (.not. ens%StdDevIsComputed) then
1909 if (mmpi_myid == 0) write(*,*) 'ens_normalize: compute Std. Dev. since it was not already done'
1910 call ens_computeStdDev( ens )
1911 end if
1912
1913 lon1 = ens%statevector_work%myLonBeg
1914 lon2 = ens%statevector_work%myLonEnd
1915 lat1 = ens%statevector_work%myLatBeg
1916 lat2 = ens%statevector_work%myLatEnd
1917 k1 = ens%statevector_work%mykBeg
1918 k2 = ens%statevector_work%mykEnd
1919 numStep = ens%statevector_work%numStep
1920
1921 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,stepIndex,memberIndex,factor)
1922 do varLevIndex = k1, k2
1923 do latIndex = lat1, lat2
1924 do lonIndex = lon1, lon2
1925 do stepIndex = 1, numStep
1926 do memberIndex = 1, ens%numMembers
1927
1928 if (ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(ens%subEnsIndexList(memberIndex),stepIndex,lonIndex,latIndex) > 0.0d0 ) then
1929 factor = 1.0d0/ens%allLev_ensStdDev_r8(varLevIndex)%onelevel(ens%subEnsIndexList(memberIndex),stepIndex,lonIndex,latIndex)
1930 else
1931 factor = 0.0d0
1932 endif
1933
1934 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
1935 real( real(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex),8) * factor, 4)
1936 end do
1937 end do
1938 end do
1939 end do
1940 end do
1941 !$OMP END PARALLEL DO
1942
1943 end subroutine ens_normalize
1944
1945 !--------------------------------------------------------------------------
1946 ! ens_removeMean
1947 !--------------------------------------------------------------------------
1948 subroutine ens_removeMean(ens)
1949 !
1950 !:Purpose: Subtract the ensemble mean from each member.
1951 !
1952 implicit none
1953
1954 ! Arguments:
1955 type(struct_ens), intent(inout) :: ens
1956
1957 ! Locals:
1958 integer :: lon1, lon2, lat1, lat2, k1, k2, numStep
1959 integer :: varLevIndex, latIndex, lonIndex, stepIndex, memberIndex
1960
1961 lon1 = ens%statevector_work%myLonBeg
1962 lon2 = ens%statevector_work%myLonEnd
1963 lat1 = ens%statevector_work%myLatBeg
1964 lat2 = ens%statevector_work%myLatEnd
1965 k1 = ens%statevector_work%mykBeg
1966 k2 = ens%statevector_work%mykEnd
1967 numStep = ens%statevector_work%numStep
1968
1969 !$OMP PARALLEL DO PRIVATE (varLevIndex,latIndex,lonIndex,stepIndex,memberIndex)
1970 do varLevIndex = k1, k2
1971 do latIndex = lat1, lat2
1972 do lonIndex = lon1, lon2
1973 do stepIndex = 1, numStep
1974 do memberIndex = 1, ens%numMembers
1975 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
1976 real( (real(ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex),8) - &
1977 ens%allLev_ensMean_r8(varLevIndex)%onelevel(ens%subEnsIndexList(memberIndex),stepIndex,lonIndex,latIndex)), 4 )
1978 end do
1979 end do
1980 end do
1981 end do
1982 end do
1983 !$OMP END PARALLEL DO
1984
1985 ens%meanIsRemoved = .true.
1986
1987 end subroutine ens_removeMean
1988
1989 !--------------------------------------------------------------------------
1990 ! ens_removeGlobalMean
1991 !--------------------------------------------------------------------------
1992 subroutine ens_removeGlobalMean(ens)
1993 !
1994 !:Purpose: Subtract the 2D global mean from each member.
1995 !
1996 implicit none
1997
1998 ! Arguments:
1999 type(struct_ens), intent(inout) :: ens
2000
2001 ! Locals:
2002 integer :: lon1, lon2, lat1, lat2, k1, k2, numStep, ierr
2003 integer :: kIndex, latIndex, lonIndex, stepIndex, memberIndex
2004 real(8) :: globalMean, globalMean_mpiglobal
2005
2006 if ( .not. ens%statevector_work%hco%global ) then
2007 call utl_abort('ens_removeGlobalMean: must never by applied to limited-area ensembles')
2008 end if
2009
2010 lon1 = ens%statevector_work%myLonBeg
2011 lon2 = ens%statevector_work%myLonEnd
2012 lat1 = ens%statevector_work%myLatBeg
2013 lat2 = ens%statevector_work%myLatEnd
2014 k1 = ens%statevector_work%mykBeg
2015 k2 = ens%statevector_work%mykEnd
2016 numStep = ens%statevector_work%numStep
2017
2018 do kIndex = k1, k2
2019 do memberIndex = 1, ens%numMembers
2020 do stepIndex = 1, numStep
2021
2022 ! Compute the domain mean
2023 globalMean = 0.d0
2024 do latIndex = lat1, lat2
2025 do lonIndex = lon1, lon2
2026 globalMean = globalMean + &
2027 real(ens%allLev_r4(kIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex),8)
2028 end do
2029 end do
2030
2031 call rpn_comm_allreduce(globalMean, globalMean_mpiglobal,1,&
2032 "mpi_double_precision","mpi_sum","GRID",ierr)
2033 globalMean_mpiglobal = globalMean_mpiglobal / &
2034 (real(ens%statevector_work%ni,8)*real(ens%statevector_work%nj,8))
2035
2036 ! Remove it
2037 do latIndex = lat1, lat2
2038 do lonIndex = lon1, lon2
2039 ens%allLev_r4(kIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
2040 ens%allLev_r4(kIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) - real(globalMean_mpiglobal,4)
2041 end do
2042 end do
2043
2044 end do
2045 end do
2046 end do
2047
2048 end subroutine ens_removeGlobalMean
2049
2050 !--------------------------------------------------------------------------
2051 ! ens_recenter
2052 !--------------------------------------------------------------------------
2053 subroutine ens_recenter(ens, recenteringMean, recenteringCoeff_opt, &
2054 recenteringCoeffLand_opt, recenteringCoeffScalar_opt, &
2055 alternativeEnsembleMean_opt, &
2056 ensembleControlMember_opt, scaleFactor_opt, &
2057 numMembersToRecenter_opt)
2058 !
2059 !:Purpose:
2060 ! To compute:
2061 ! ..math::
2062 ! x_recentered =
2063 ! scaleFactor*x_original
2064 ! + recenteringCoeff*( x_recenteringMean
2065 ! - scaleFactor*x_ensembleMean
2066 ! )
2067 implicit none
2068
2069 ! Arguments:
2070 type(struct_ens), intent(inout) :: ens
2071 type(struct_gsv), intent(in) :: recenteringMean
2072 type(struct_gsv), optional, intent(in) :: alternativeEnsembleMean_opt
2073 type(struct_gsv), optional, intent(in) :: ensembleControlMember_opt
2074 real(8), optional, intent(in) :: recenteringCoeff_opt(:,:)
2075 real(8), optional, intent(in) :: recenteringCoeffLand_opt(:)
2076 real(8), optional, intent(in) :: recenteringCoeffScalar_opt
2077 real(8), optional, intent(in) :: scaleFactor_opt(:)
2078 integer, optional, intent(in) :: numMembersToRecenter_opt
2079
2080 ! Locals:
2081 real(8), pointer :: ptr4d_r8(:,:,:,:)
2082 real(8), pointer :: alternativeEnsembleMean_r8(:,:,:,:)
2083 real(8), pointer :: ptr4d_ensembleControlmember_r8(:,:,:,:)
2084 real(8) :: scaleFactor(vco_maxNumLevels)
2085 real(8) :: recenteringCoeffArray(vco_maxNumLevels,ens%numMembers)
2086 real(8) :: recenteringCoeffArrayLand(ens%numMembers)
2087 real(8) :: recenteringCoeffArrayUsed(ens%numMembers)
2088 real(8) :: increment, thisScaleFactor
2089 real(4), pointer :: ptr4d_r4(:,:,:,:)
2090 integer :: lon1, lon2, lat1, lat2, k1, k2, numStep, numMembersToRecenter
2091 integer :: varLevIndex, latIndex, lonIndex, stepIndex, memberIndex, levIndex
2092 character(len=4) :: varLevel
2093 character(len=2) :: varKind
2094
2095 ! if an alternative mean is not provided, we need to ensure ens mean is present
2096 if ( .not. present(alternativeEnsembleMean_opt)) then
2097 if ( .not. ens%meanIsComputed ) then
2098 if (mmpi_myid == 0) write(*,*) 'ens_recenter: compute Mean since it was not already done'
2099 call ens_computeMean( ens )
2100 end if
2101 end if
2102
2103 if ( present(recenteringCoeff_opt) ) then
2104 recenteringCoeffArray(:,:) = recenteringCoeff_opt(:,:)
2105 else if ( present(recenteringCoeffScalar_opt) ) then
2106 recenteringCoeffArray(:,:) = recenteringCoeffScalar_opt
2107 else
2108 call utl_abort('ens_recenter: Must specify recenteringCoeff_opt or recenteringCoeffScalar_opt')
2109 end if
2110
2111 if ( present(scaleFactor_opt) ) then
2112 ! scaleFactor cannot be used at the same time as a recenteringCoeff different from 1.0
2113 if ( any (abs(recenteringCoeffArray(:,:) - 1.0D0) > 1.0D-5) ) then
2114 call utl_abort('ens_recenter: recenteringCoeff must be equal to 1.0 when using scaleFactor')
2115 end if
2116 scaleFactor = scaleFactor_opt
2117 else
2118 scaleFactor(:) = 1.0D0
2119 end if
2120
2121 if ( present(recenteringCoeffLand_opt) ) then
2122 if (any(recenteringCoeffLand_opt < 0.0D0)) then
2123 ! negative coeff specified for land, apply same coeff as other variables
2124 recenteringCoeffArrayLand(:) = recenteringCoeffArray(max(1,ens_getNumLev(ens,'MM')),:)
2125 else
2126 ! specified coeff for land variables used for all members
2127 write(*,*) 'ens_recenter: different recentering applied to land variables:', &
2128 recenteringCoeffLand_opt(:)
2129 recenteringCoeffArrayLand(:) = recenteringCoeffLand_opt(:)
2130 end if
2131 else
2132 ! coeff for land not specified, apply same coeff as other variables
2133 recenteringCoeffArrayLand(:) = recenteringCoeffArray(max(1,ens_getNumLev(ens,'MM')),:)
2134 end if
2135
2136 if (present(numMembersToRecenter_opt)) then
2137 numMembersToRecenter = numMembersToRecenter_opt
2138 else
2139 numMembersToRecenter = ens%numMembers
2140 end if
2141
2142 lon1 = ens%statevector_work%myLonBeg
2143 lon2 = ens%statevector_work%myLonEnd
2144 lat1 = ens%statevector_work%myLatBeg
2145 lat2 = ens%statevector_work%myLatEnd
2146 k1 = ens%statevector_work%mykBeg
2147 k2 = ens%statevector_work%mykEnd
2148 numStep = ens%statevector_work%numStep
2149
2150 nullify(ptr4d_r4, ptr4d_r8)
2151 if (gsv_getDataKind(recenteringMean) == 8) then
2152 call gsv_getField(recenteringMean,ptr4d_r8)
2153 else
2154 call gsv_getField(recenteringMean,ptr4d_r4)
2155 end if
2156 if(present(alternativeEnsembleMean_opt)) then
2157 call gsv_getField(alternativeEnsembleMean_opt,alternativeEnsembleMean_r8)
2158 else
2159 nullify(alternativeEnsembleMean_r8)
2160 end if
2161
2162 if (present(ensembleControlMember_opt)) then
2163 call gsv_getField(ensembleControlMember_opt,ptr4d_ensembleControlmember_r8)
2164 else
2165 nullify(ptr4d_ensembleControlmember_r8)
2166 end if
2167
2168 !$OMP PARALLEL DO PRIVATE(varLevIndex,varLevel,varKind,levIndex,thisScaleFactor), &
2169 !$OMP PRIVATE(latIndex,lonIndex,stepIndex,memberIndex,increment,recenteringCoeffArrayUsed)
2170 do varLevIndex = k1, k2
2171
2172 ! define scaling factor as a function of vertical level and variable type
2173 varLevel = vnl_varLevelFromVarname(ens_getVarNameFromK(ens, varLevIndex))
2174 if ( trim(varLevel) == 'SF' .or. trim(varLevel) == 'SFMM' .or. trim(varLevel) == 'SFTH' ) then
2175 ! use lowest momentum level for surface variables
2176 levIndex = ens_getNumLev(ens, 'MM')
2177 else if ( (trim(varLevel) == 'MM') .and. (ens%statevector_work%vco%Vcode == 5002) ) then
2178 levIndex = ens_getLevFromK(ens, varLevIndex) + 1
2179 else
2180 levIndex = ens_getLevFromK(ens, varLevIndex)
2181 end if
2182 thisScaleFactor = scaleFactor(levIndex)
2183
2184 ! determine which recentering coeff are used: general or land-specific
2185 varKind = vnl_varKindFromVarname(ens_getVarNameFromK(ens, varLevIndex))
2186 if ( varKind == 'LD' ) then
2187 recenteringCoeffArrayUsed(:) = recenteringCoeffArrayLand(:)
2188 else
2189 recenteringCoeffArrayUsed(:) = recenteringCoeffArray(levIndex,:)
2190 end if
2191
2192 do latIndex = lat1, lat2
2193 do lonIndex = lon1, lon2
2194 do stepIndex = 1, numStep
2195 if(present(alternativeEnsembleMean_opt)) then
2196 if (associated(ptr4d_r8)) then
2197 increment = ptr4d_r8(lonIndex,latIndex,varLevIndex,stepIndex) - &
2198 thisScaleFactor * &
2199 alternativeEnsembleMean_r8(lonIndex,latIndex,varLevIndex,stepIndex)
2200 else
2201 increment = real(ptr4d_r4(lonIndex,latIndex,varLevIndex,stepIndex),8) - &
2202 thisScaleFactor * &
2203 alternativeEnsembleMean_r8(lonIndex,latIndex,varLevIndex,stepIndex)
2204 end if
2205 else
2206 if (associated(ptr4d_r8)) then
2207 increment = ptr4d_r8(lonIndex,latIndex,varLevIndex,stepIndex) - &
2208 thisScaleFactor * &
2209 ens%allLev_ensMean_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex)
2210 else
2211 increment = real(ptr4d_r4(lonIndex,latIndex,varLevIndex,stepIndex),8) - &
2212 thisScaleFactor * &
2213 ens%allLev_ensMean_r8(varLevIndex)%onelevel(1,stepIndex,lonIndex,latIndex)
2214 end if
2215 end if
2216 if (present(ensembleControlMember_opt)) then
2217 ptr4d_ensembleControlMember_r8(lonIndex,latIndex,varLevIndex,stepIndex) = &
2218 thisScaleFactor * &
2219 ptr4d_ensembleControlMember_r8(lonIndex,latIndex,varLevIndex,stepIndex) + &
2220 recenteringCoeffArrayUsed(1)*increment
2221 else
2222 do memberIndex = 1, numMembersToRecenter
2223 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex) = &
2224 real( real(thisScaleFactor * &
2225 ens%allLev_r4(varLevIndex)%onelevel(memberIndex,stepIndex,lonIndex,latIndex),8) + &
2226 recenteringCoeffArrayUsed(memberIndex)*increment, 4)
2227 end do
2228 end if
2229 end do
2230 end do
2231 end do
2232 end do
2233 !$OMP END PARALLEL DO
2234
2235 end subroutine ens_recenter
2236
2237 !--------------------------------------------------------------------------
2238 ! ens_readEnsemble
2239 !--------------------------------------------------------------------------
2240 subroutine ens_readEnsemble(ens, ensPathName, biPeriodic, &
2241 vco_file_opt, varNames_opt, checkModelTop_opt, &
2242 containsFullField_opt, ignoreDate_opt)
2243 !
2244 !:Purpose: Read the ensemble from disk in parallel and do mpi communication
2245 ! so that all members for a given lat-lon tile are present on each
2246 ! mpi task.
2247 !
2248 implicit none
2249
2250 ! Arguments:
2251 type(struct_ens), intent(inout) :: ens
2252 character(len=*), intent(in) :: ensPathName
2253 logical, intent(in) :: biPeriodic
2254 character(len=*), optional, intent(in) :: varNames_opt(:)
2255 type(struct_vco), pointer, optional, intent(in) :: vco_file_opt
2256 logical, optional, intent(in) :: checkModelTop_opt
2257 logical, optional, intent(in) :: containsFullField_opt
2258 logical, optional, intent(in) :: ignoreDate_opt
2259
2260 ! Locals:
2261 type(struct_gsv) :: statevector_file_r4, statevector_hint_r4, statevector_member_r4
2262 type(struct_hco), pointer :: hco_file, hco_ens, hco_coregrid
2263 type(struct_vco), pointer :: vco_file, vco_ens
2264 real(4), allocatable :: gd_send_r4(:,:,:,:)
2265 real(4), allocatable :: gd_recv_r4(:,:,:,:)
2266 real(4), pointer :: ptr3d_r4(:,:,:)
2267 integer,pointer :: dateStampList(:)
2268 integer :: batchIndex, nsize, ierr
2269 integer :: yourid, youridx, youridy
2270 integer, allocatable :: readFilePE(:), memberIndexFromMemberStep(:), stepIndexFromMemberStep(:)
2271 integer, allocatable :: batchIndexFromMemberStep(:)
2272 integer :: sendsizes(mmpi_nprocs), recvsizes(mmpi_nprocs), senddispls(mmpi_nprocs), recvdispls(mmpi_nprocs)
2273 integer :: lonPerPEmax, latPerPEmax, ni, nj, numK, numStep, numMembers, numLevelsToSend2
2274 integer :: memberIndex, memberIndex2, stepIndex, stepIndex2, procIndex, memberStepIndex, memberStepIndex2
2275 integer :: kIndexBeg, kIndexEnd, kCount, memberStepIndexStart, lastReadFilePE
2276 character(len=256) :: ensFileName
2277 character(len=2) :: typvar
2278 character(len=12) :: etiket
2279 character(len=4), pointer :: anlVar(:)
2280 logical :: thisProcIsAsender(mmpi_nprocs), doMpiCommunication
2281 logical :: verticalInterpNeeded, horizontalInterpNeeded, horizontalPaddingNeeded
2282 logical :: checkModelTop, containsFullField, ignoreDate
2283 character(len=4), pointer :: varNames(:)
2284 integer, parameter :: numLevelsToSend = 10
2285
2286 write(*,*) 'ens_readEnsemble: starting'
2287 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2288
2289 if ( .not. ens%allocated ) then
2290 call utl_abort('ens_readEnsemble: ensemble object not allocated!')
2291 end if
2292
2293 !
2294 !- 1. Initial setup
2295 !
2296 lonPerPEmax = ens%statevector_work%lonPerPEmax
2297 latPerPEmax = ens%statevector_work%latPerPEmax
2298 ni = ens%statevector_work%ni
2299 nj = ens%statevector_work%nj
2300 numK = ens%statevector_work%nk
2301 numStep = ens%statevector_work%numStep
2302 numMembers = ens%numMembers
2303
2304 dateStampList => ens%statevector_work%dateStampList
2305
2306 ens%ensPathName = trim(ensPathName)
2307
2308 ! Determine which MPI tasks read which members/steps to minimize file copies to ram disk
2309 allocate(batchIndexFromMemberStep(numMembers*numStep))
2310 allocate(readFilePE(numMembers*numStep))
2311 allocate(stepIndexFromMemberStep(numMembers*numStep))
2312 allocate(memberIndexFromMemberStep(numMembers*numStep))
2313 do stepIndex = 1, numStep
2314 do memberIndex = 1, numMembers
2315 memberStepIndex = ((stepIndex-1)*numMembers) + memberIndex
2316 stepIndexFromMemberStep(memberStepIndex) = stepIndex
2317 memberIndexFromMemberStep(memberStepIndex) = memberIndex
2318
2319 if (memberStepIndex == 1) then
2320 ! Very first member/step
2321 readFilePE(memberStepIndex) = 0
2322 batchIndexFromMemberStep(memberStepIndex) = 1
2323 else
2324 ! Increment MPI task ID and keep same batch
2325 readFilePE(memberStepIndex) = readFilePE(memberStepIndex-1) + 1
2326 batchIndexFromMemberStep(memberStepIndex) = batchIndexFromMemberStep(memberStepIndex-1)
2327 end if
2328
2329 ! Decide if we need to move to the next batch
2330 if (memberIndex == 1) then
2331 if (readFilePE(memberStepIndex) == 0) then
2332 ! First MPI task reading member 1, try to fit all others in this batch
2333 lastReadFilePE = numMembers - 1
2334 else
2335 ! Check if we can fit this full time step in this batch
2336 if (lastReadFilePE + numMembers < mmpi_nprocs) then
2337 lastReadFilePE = lastReadFilePE + numMembers
2338 end if
2339 ! If numMembers > nprocs, move to next batch
2340 if (numMembers > mmpi_nprocs) then
2341 readFilePE(memberStepIndex) = 0
2342 batchIndexFromMemberStep(memberStepIndex) = batchIndexFromMemberStep(memberStepIndex-1)+ 1
2343 lastReadFilePE = numMembers - 1
2344 end if
2345 end if
2346 ! Ensure we limit ourselves to the total number of MPI tasks
2347 lastReadFilePE = min(lastreadFilePE, mmpi_nprocs - 1)
2348 end if
2349 ! Move to next batch if we reached lastReadFilePE
2350 if (readFilePE(memberStepIndex) == lastReadFilePE + 1) then
2351 readFilePE(memberStepIndex) = 0
2352 batchIndexFromMemberStep(memberStepIndex) = batchIndexFromMemberStep(memberStepIndex-1)+ 1
2353 lastReadFilePE = min(numMembers - memberIndex, mmpi_nprocs - 1)
2354 end if
2355
2356 if (mmpi_myid == 0) then
2357 write(*,*) 'ens_readEnsemble: batchIndex, memberIndex, stepIndex, memberStepIndex, readFilePE = ', &
2358 batchIndexFromMemberStep(memberStepIndex), memberIndex, stepIndex, memberStepIndex, &
2359 readFilePE(memberStepIndex)
2360 end if
2361
2362 end do
2363 end do
2364
2365 ! the default is to check whether output grid has a higher top than input grid during vertical interpolation
2366 if ( present(checkModelTop_opt) ) then
2367 checkModelTop = checkModelTop_opt
2368 else
2369 checkModelTop = .true.
2370 end if
2371
2372 ! the default is to NOT ignore the date - can only ignore if numStep == 1
2373 if ( present(ignoreDate_opt) ) then
2374 ignoreDate = ignoreDate_opt
2375 else
2376 ignoreDate = .false.
2377 end if
2378 if ( ignoreDate .and. (numStep > 1) ) then
2379 call utl_abort('ens_readEnsemble: cannot ignore date if numStep > 1')
2380 end if
2381
2382 ! Set up hco and vco for ensemble files
2383 call fln_ensFileName(ensFileName, ensPathName, memberIndex_opt=1, copyToRamDisk_opt=.false., &
2384 fileMemberIndex1_opt=ens%fileMemberIndex1)
2385
2386 nullify(anlVar)
2387 call gsv_varNamesList(anlVar)
2388 nullify(hco_file)
2389 call hco_SetupFromFile(hco_file, ensFileName, ' ', 'ENSFILEGRID', varName_opt=anlVar(1))
2390 if ( present(vco_file_opt) ) then
2391 ! use the input vertical grid provided
2392 vco_file => vco_file_opt
2393 else
2394 ! find the info from the ensemble files
2395 nullify(vco_file)
2396 if ( mmpi_myid == 0 ) then
2397 call vco_SetupFromFile(vco_file, ensFileName)
2398 end if
2399 call vco_mpiBcast(vco_file)
2400 end if
2401 hco_ens => gsv_getHco(ens%statevector_work)
2402 hco_coregrid => ens%hco_core
2403 vco_ens => gsv_getVco(ens%statevector_work)
2404 horizontalInterpNeeded = (.not. hco_equal(hco_ens, hco_file))
2405 verticalInterpNeeded = (.not. vco_equal(vco_ens, vco_file))
2406
2407 ! More efficient handling of common case where input is on Z grid, analysis in on G grid
2408 if ( hco_file%grtyp == 'Z' .and. hco_ens%grtyp == 'G' ) then
2409 if ( hco_file%ni == (hco_ens%ni+1) ) then
2410 write(*,*) 'ens_readEnsemble: no interpolation done for equivalent Gaussian grid stored as a Z grid'
2411 horizontalInterpNeeded = .false.
2412 end if
2413 end if
2414 ! In limited-area mode, avoid horizontal interpolation when the ensemble is on the coregrid
2415 horizontalPaddingNeeded = .false.
2416 if ( .not. hco_file%global ) then
2417 if ( hco_file%ni == hco_coregrid%ni .and. hco_file%nj == hco_coregrid%nj ) then
2418 if (mmpi_myid == 0) then
2419 write(*,*) 'ens_readEnsemble: no interpolation needed for ensemble on the limited-area coregrid'
2420 end if
2421 horizontalInterpNeeded = .false.
2422 if ( hco_file%ni /= hco_ens%ni .or. hco_file%nj /= hco_ens%nj ) then
2423 if (mmpi_myid == 0) then
2424 write(*,*) 'ens_readEnsemble: horizontal padding needed for limited-area ensemble'
2425 end if
2426 horizontalPaddingNeeded = .true.
2427 end if
2428 end if
2429 end if
2430
2431 if (mmpi_myid == 0) then
2432 write(*,*)
2433 write(*,*) 'ens_readEnsemble: dateStampList=',dateStampList(1:numStep)
2434 write(*,*)
2435 if (horizontalInterpNeeded ) write(*,*) 'ens_readEnsemble: HORIZONTAL interpolation is needed'
2436 if (verticalInterpNeeded ) write(*,*) 'ens_readEnsemble: VERTICAL interpolation is needed'
2437 if (horizontalPaddingNeeded) write(*,*) 'ens_readEnsemble: HORIZONTAL padding is needed'
2438 end if
2439
2440 ! Input type
2441 if (present(containsFullField_opt)) then
2442 containsFullField = containsFullField_opt
2443 else
2444 containsFullField = .true.
2445 end if
2446 if (mmpi_myid == 0) then
2447 write(*,*)
2448 write(*,*) 'ens_readEnsemble: containsFullField = ', containsFullField
2449 end if
2450
2451 !
2452 !- 2. Ensemble forecasts reading loop
2453 !
2454
2455 nullify(varNames)
2456 if (present(varNames_opt)) then
2457 allocate(varNames(size(varNames_opt)))
2458 varNames(:) = varNames_opt(:)
2459 else
2460 call gsv_varNamesList(varNames)
2461 end if
2462
2463 !- 2.1 Loop on time, ensemble member, variable, level
2464 memberStepIndexStart = 1
2465 stepLoop: do stepIndex = 1, numStep
2466 write(*,*) ' '
2467 write(*,*) 'ens_readEnsemble: starting to read time level ', stepIndex
2468
2469 memberLoop: do memberIndex = 1, numMembers
2470
2471 memberStepIndex = ((stepIndex-1)*numMembers) + memberIndex
2472 batchIndex = batchIndexFromMemberStep(memberStepIndex)
2473 if (mmpi_myid == readFilePE(memberStepIndex)) then
2474
2475 ! allocate the needed statevector objects
2476 call gsv_allocate(statevector_member_r4, 1, hco_ens, vco_ens, &
2477 datestamp_opt = dateStampList(stepIndex), mpi_local_opt = .false., &
2478 varNames_opt = varNames, dataKind_opt = 4, &
2479 hInterpolateDegree_opt = ens%hInterpolateDegree)
2480 if (horizontalInterpNeeded .or. verticalInterpNeeded .or. horizontalPaddingNeeded) then
2481 call gsv_allocate(statevector_file_r4, 1, hco_file, vco_file, &
2482 datestamp_opt = dateStampList(stepIndex), mpi_local_opt = .false., &
2483 varNames_opt = varNames, dataKind_opt = 4, &
2484 hInterpolateDegree_opt = ens%hInterpolateDegree)
2485 end if
2486 if (verticalInterpNeeded) then
2487 call gsv_allocate(statevector_hint_r4, 1, hco_ens, vco_file, &
2488 datestamp_opt = dateStampList(stepIndex), mpi_local_opt = .false., &
2489 varNames_opt = varNames, dataKind_opt = 4, &
2490 hInterpolateDegree_opt = ens%hInterpolateDegree)
2491 end if
2492 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2493
2494 ! Read the file
2495 call fln_ensFileName(ensFileName, ensPathName, memberIndex_opt=memberIndex, &
2496 fileMemberIndex1_opt=ens%fileMemberIndex1)
2497 typvar = ' '
2498 etiket = ' '
2499 if (.not. horizontalInterpNeeded .and. &
2500 .not. verticalInterpNeeded .and. &
2501 .not. horizontalPaddingNeeded ) then
2502 call gio_readFile(statevector_member_r4, ensFileName, etiket, typvar, &
2503 containsFullField, ignoreDate_opt=ignoreDate)
2504 else
2505 call gio_readFile(statevector_file_r4, ensFileName, etiket, typvar, &
2506 containsFullField, ignoreDate_opt=ignoreDate)
2507 end if
2508
2509 ! Remove file from ram disk if no longer needed
2510 if ( all(readFilePE(memberStepIndex+1:numMembers*numStep) /= mmpi_myid) .or. &
2511 (stepIndex == numStep) .or. &
2512 (batchIndex == maxval(batchIndexFromMemberStep(:))) ) then
2513 ierr = ram_remove(ensFileName)
2514 end if
2515
2516 ! do any required interpolation
2517 if (horizontalInterpNeeded .and. verticalInterpNeeded) then
2518 call int_hInterp_gsv(statevector_file_r4, statevector_hint_r4)
2519 call int_vInterp_gsv( statevector_hint_r4, statevector_member_r4, &
2520 Ps_in_hPa_opt=.true.,checkModelTop_opt=checkModelTop)
2521
2522 else if (horizontalInterpNeeded .and. .not. verticalInterpNeeded) then
2523 call int_hInterp_gsv(statevector_file_r4, statevector_member_r4)
2524
2525 else if (.not. horizontalInterpNeeded .and. verticalInterpNeeded) then
2526 if (horizontalPaddingNeeded) then
2527 call gsv_hPad(statevector_file_r4, statevector_hint_r4)
2528 else
2529 call gsv_copy(statevector_file_r4, statevector_hint_r4)
2530 end if
2531 call int_vInterp_gsv( statevector_hint_r4, statevector_member_r4, &
2532 Ps_in_hPa_opt=.true.,checkModelTop_opt=checkModelTop)
2533
2534 else if (horizontalPaddingNeeded) then
2535 call gsv_hPad(statevector_file_r4, statevector_member_r4)
2536 end if
2537
2538 ! unit conversion
2539 call gio_fileUnitsToStateUnits(statevector_member_r4, containsFullField)
2540
2541 ! Create bi-periodic forecasts when using scale-dependent localization in LAM mode
2542 if ( .not. hco_ens%global .and. biperiodic ) then
2543 call gsv_getField(statevector_member_r4,ptr3d_r4)
2544 call lgt_mach_r4(ptr3d_r4, & ! INOUT
2545 ni, nj, statevector_member_r4%nk) ! IN
2546 end if
2547
2548 ! copy over some time related and other parameters
2549 ens%statevector_work%deet = statevector_member_r4%deet
2550 ens%statevector_work%dateOriginList(stepIndex) = statevector_member_r4%dateOriginList(1)
2551 ens%statevector_work%npasList(stepIndex) = statevector_member_r4%npasList(1)
2552 ens%statevector_work%ip2List(stepIndex) = statevector_member_r4%ip2List(1)
2553 ens%statevector_work%etiket = statevector_member_r4%etiket
2554 ens%statevector_work%onPhysicsGrid(:) = statevector_member_r4%onPhysicsGrid(:)
2555 ens%statevector_work%hco_physics => statevector_member_r4%hco_physics
2556 ! if it exists, copy over mask from member read on task 0, which should always read
2557 if(mmpi_myid == 0) then
2558 call gsv_copyMask(stateVector_member_r4, ens%stateVector_work)
2559 end if
2560
2561 end if ! locally read one member
2562
2563 ! MPI communication: from 1 ensemble member per process to 1 lat-lon tile per process
2564 if (memberStepIndex == numStep*numMembers) then
2565 ! last member/step was read, do last communication
2566 doMpiCommunication = .true.
2567 else if (batchIndex < batchIndexFromMemberStep(memberStepIndex+1)) then
2568 ! next member/step is in next batch, do communication
2569 doMpiCommunication = .true.
2570 else
2571 ! do not do communication, still reading members/steps
2572 doMpiCommunication = .false.
2573 end if
2574
2575 if (doMpiCommunication) then
2576 write(*,*) 'ens_readEnsemble: Do communication for batchIndex = ', batchIndex
2577 write(*,*) ' for the memberStepIndex range = ', memberStepIndexStart, memberStepIndex
2578
2579 ! determine which tasks have something to send and let everyone know
2580 do procIndex = 1, mmpi_nprocs
2581 thisProcIsAsender(procIndex) = .false.
2582 if ( mmpi_myid == (procIndex-1) .and. gsv_isAllocated(stateVector_member_r4) ) then
2583 thisProcIsAsender(procIndex) = .true.
2584 end if
2585 call rpn_comm_bcast(thisProcIsAsender(procIndex), 1, &
2586 'MPI_LOGICAL', procIndex-1, 'GRID', ierr)
2587 end do
2588
2589 do kIndexBeg = 1, numK, numLevelsToSend
2590 kIndexEnd = min(numK,kIndexBeg+numLevelsToSend-1)
2591 numLevelsToSend2 = kIndexEnd - kIndexBeg + 1
2592
2593 ! prepare for alltoallv
2594 nsize = lonPerPEmax * latPerPEmax * numLevelsToSend2
2595
2596 ! only send the data from tasks with data, same amount to all
2597 sendsizes(:) = 0
2598 if ( gsv_isAllocated(stateVector_member_r4) ) then
2599 do procIndex = 1, mmpi_nprocs
2600 sendsizes(procIndex) = nsize
2601 end do
2602 end if
2603 senddispls(1) = 0
2604 do procIndex = 2, mmpi_nprocs
2605 senddispls(procIndex) = senddispls(procIndex-1) + sendsizes(procIndex-1)
2606 end do
2607
2608 ! all tasks recv only from those with data
2609 recvsizes(:) = 0
2610 do procIndex = 1, mmpi_nprocs
2611 if ( thisProcIsAsender(procIndex) ) then
2612 recvsizes(procIndex) = nsize
2613 end if
2614 end do
2615 recvdispls(1) = 0
2616 do procIndex = 2, mmpi_nprocs
2617 recvdispls(procIndex) = recvdispls(procIndex-1) + recvsizes(procIndex-1)
2618 end do
2619
2620 if (gsv_isAllocated(statevector_member_r4)) then
2621 allocate(gd_send_r4(lonPerPEmax,latPerPEmax,numLevelsToSend2,mmpi_nprocs))
2622 gd_send_r4(:,:,:,:) = 0.0
2623 call gsv_getField(statevector_member_r4,ptr3d_r4)
2624 !$OMP PARALLEL DO PRIVATE(youridy,youridx,yourid)
2625 do youridy = 0, (mmpi_npey-1)
2626 do youridx = 0, (mmpi_npex-1)
2627 yourid = youridx + youridy*mmpi_npex
2628 gd_send_r4(1:ens%statevector_work%allLonPerPE(youridx+1), &
2629 1:ens%statevector_work%allLatPerPE(youridy+1), :, yourid+1) = &
2630 ptr3d_r4(ens%statevector_work%allLonBeg(youridx+1):ens%statevector_work%allLonEnd(youridx+1), &
2631 ens%statevector_work%allLatBeg(youridy+1):ens%statevector_work%allLatEnd(youridy+1), kIndexBeg:kIndexEnd)
2632 end do
2633 end do
2634 !$OMP END PARALLEL DO
2635 else
2636 allocate(gd_send_r4(1,1,1,1))
2637 gd_send_r4(:,:,:,:) = 0.0
2638 end if
2639 allocate(gd_recv_r4(lonPerPEmax,latPerPEmax,numLevelsToSend2,max(mmpi_nprocs,numMembers)))
2640 gd_recv_r4(:,:,:,:) = 0.0
2641
2642 if (mmpi_nprocs.gt.1) then
2643 call mpi_alltoallv(gd_send_r4, sendsizes, senddispls, mmpi_datyp_real4, &
2644 gd_recv_r4, recvsizes, recvdispls, mmpi_datyp_real4, &
2645 mmpi_comm_grid, ierr)
2646 else
2647 gd_recv_r4(:,:,:,1) = gd_send_r4(:,:,:,1)
2648 end if
2649
2650 !$OMP PARALLEL DO PRIVATE(kCount,memberStepIndex2,memberIndex2,stepIndex2,yourid)
2651 do kCount = 1, numLevelsToSend2
2652 do memberStepIndex2 = memberStepIndexStart, memberStepIndex
2653 memberIndex2 = memberIndexFromMemberStep(memberStepIndex2)
2654 stepIndex2 = stepIndexFromMemberStep(memberStepIndex2)
2655 yourid = readFilePE(memberStepIndex2)
2656 ens%allLev_r4(kCount+kIndexBeg-1)%onelevel(memberIndex2,stepIndex2, :, :) = &
2657 gd_recv_r4(1:ens%statevector_work%lonPerPE, 1:ens%statevector_work%latPerPE, &
2658 kCount, yourid+1)
2659 end do
2660 end do
2661 !$OMP END PARALLEL DO
2662
2663 deallocate(gd_send_r4)
2664 deallocate(gd_recv_r4)
2665
2666 end do ! kIndexBeg
2667
2668 ! deallocate the needed statevector objects
2669 if (gsv_isAllocated(statevector_member_r4)) then
2670 call gsv_deallocate(statevector_member_r4)
2671 end if
2672 if (gsv_isAllocated(statevector_file_r4)) then
2673 call gsv_deallocate(statevector_file_r4)
2674 end if
2675 if (gsv_isAllocated(statevector_hint_r4)) then
2676 call gsv_deallocate(statevector_hint_r4)
2677 end if
2678
2679 memberStepIndexStart = memberStepIndex + 1
2680
2681 end if ! MPI communication
2682
2683 end do memberLoop
2684
2685 end do stepLoop
2686
2687 call gsv_communicateTimeParams(ens%statevector_work)
2688 call ocm_communicateMask(ens%statevector_work%oceanMask)
2689
2690 deallocate(datestamplist)
2691 call hco_deallocate(hco_file)
2692 if ( .not. present(vco_file_opt) ) then
2693 call vco_deallocate(vco_file)
2694 end if
2695 deallocate(readFilePE)
2696 deallocate(batchIndexFromMemberStep)
2697 deallocate(stepIndexFromMemberStep)
2698 deallocate(memberIndexFromMemberStep)
2699
2700 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2701 write(*,*) 'ens_readEnsemble: finished reading and communicating ensemble members...'
2702
2703 end subroutine ens_readEnsemble
2704
2705 !--------------------------------------------------------------------------
2706 ! ens_writeEnsemble
2707 !--------------------------------------------------------------------------
2708 subroutine ens_writeEnsemble(ens, ensPathName, ensFileNamePrefix, &
2709 etiket, typvar, &
2710 etiketAppendMemberNumber_opt, varNames_opt, &
2711 ip3_opt, containsFullField_opt, numBits_opt, &
2712 resetTimeParams_opt)
2713 !
2714 !:Purpose: Write the ensemble to disk by doing mpi transpose so that
2715 ! each mpi task can write a single member in parallel.
2716 !
2717 implicit none
2718
2719 ! Arguments:
2720 type(struct_ens), intent(inout) :: ens
2721 character(len=*), intent(in) :: ensPathName
2722 character(len=*), intent(in) :: ensFileNamePrefix
2723 character(len=*), intent(in) :: etiket
2724 character(len=*), intent(in) :: typvar
2725 character(len=*), optional, intent(in) :: varNames_opt(:)
2726 integer, optional, intent(in) :: ip3_opt
2727 integer, optional, intent(in) :: numBits_opt
2728 logical, optional, intent(in) :: etiketAppendMemberNumber_opt
2729 logical, optional, intent(in) :: containsFullField_opt
2730 logical, optional, intent(in) :: resetTimeParams_opt
2731
2732 ! Locals:
2733 type(struct_gsv) :: statevector_member_r4
2734 type(struct_hco), pointer :: hco_ens
2735 type(struct_vco), pointer :: vco_ens
2736 real(4), allocatable :: gd_send_r4(:,:,:,:)
2737 real(4), allocatable :: gd_recv_r4(:,:,:,:)
2738 real(4), pointer :: ptr3d_r4(:,:,:)
2739 integer, allocatable :: dateStampList(:)
2740 integer :: batchIndex, nsize, ierr
2741 integer :: yourid, youridx, youridy
2742 integer :: writeFilePE(1000)
2743 integer :: lonPerPE, lonPerPEmax, latPerPE, latPerPEmax, ni, nj
2744 integer :: numK, numStep, numlevelstosend, numlevelstosend2
2745 integer :: memberIndex, memberIndex2, stepIndex, kIndexBeg, kIndexEnd, kCount
2746 integer :: ip3, ensFileExtLength, maximumBaseEtiketLength
2747 character(len=256) :: ensFileName
2748 character(len=12) :: etiketStr ! this is the etiket that will be used to write files
2749 !! The two next declarations are sufficient until we reach 10^10 members
2750 character(len=10) :: memberIndexStr ! this is the member number in a character string
2751 character(len=10) :: ensFileExtLengthStr ! this is a string containing the same number as 'ensFileExtLength'
2752 character(len=4), pointer :: varNamesInEns(:)
2753 logical :: containsFullField
2754
2755 write(*,*) 'ens_writeEnsemble: starting'
2756 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2757
2758 if ( .not. ens%allocated ) then
2759 call utl_abort('ens_writeEnsemble: ensemble object not allocated!')
2760 end if
2761
2762 !- 1. Initial setup
2763
2764 nullify(varNamesInEns)
2765 if (present(varNames_opt)) then
2766 allocate(varNamesInEns(size(varNames_opt)))
2767 varNamesInEns(:) = varNames_opt(:)
2768 else
2769 call gsv_varNamesList(varNamesInEns, ens%statevector_work)
2770 end if
2771
2772 if (present(ip3_opt)) then
2773 ip3 = ip3_opt
2774 else
2775 ip3 = 0
2776 end if
2777
2778 if (present(resetTimeParams_opt)) then
2779 if (resetTimeParams_opt) then
2780 call gsv_resetTimeParams(ens%statevector_work)
2781 end if
2782 end if
2783
2784 lonPerPE = ens%statevector_work%lonPerPE
2785 latPerPE = ens%statevector_work%latPerPE
2786 lonPerPEmax = ens%statevector_work%lonPerPEmax
2787 latPerPEmax = ens%statevector_work%latPerPEmax
2788 ni = ens%statevector_work%ni
2789 nj = ens%statevector_work%nj
2790 numK = ens%statevector_work%nk
2791 numStep = ens%statevector_work%numStep
2792
2793 ens%ensPathName = trim(ensPathName)
2794
2795 ! Memory allocation
2796 numLevelsToSend = 10
2797 allocate(gd_send_r4(lonPerPEmax,latPerPEmax,numLevelsToSend,mmpi_nprocs))
2798 allocate(gd_recv_r4(lonPerPEmax,latPerPEmax,numLevelsToSend,mmpi_nprocs))
2799 gd_send_r4(:,:,:,:) = 0.0
2800 gd_recv_r4(:,:,:,:) = 0.0
2801
2802 allocate(dateStampList(numStep))
2803 call tim_getstamplist(dateStampList,numStep,tim_getDatestamp())
2804
2805 do memberIndex = 1, ens%numMembers
2806 writeFilePE(memberIndex) = mod(memberIndex-1,mmpi_nprocs)
2807 end do
2808
2809 hco_ens => gsv_getHco(ens%statevector_work)
2810 vco_ens => gsv_getVco(ens%statevector_work)
2811
2812 if (mmpi_myid == 0) then
2813 write(*,*)
2814 write(*,*) 'ens_writeEnsemble: dateStampList=',dateStampList(1:numStep)
2815 write(*,*)
2816 end if
2817
2818 !
2819 !- 2. Ensemble forecasts writing loop
2820 !
2821
2822 !- 2.1 Loop on time, ensemble member, variable, level
2823 do stepIndex = 1, numStep
2824 write(*,*) ' '
2825 write(*,*) 'ens_writeEnsemble: starting to write time level ', stepIndex
2826
2827 ! allocate the needed statevector objects
2828 call gsv_allocate(statevector_member_r4, 1, hco_ens, vco_ens, &
2829 datestamp_opt=dateStampList(stepIndex), mpi_local_opt=.false., &
2830 varNames_opt=varNamesInEns, dataKind_opt=4)
2831
2832 ! copy over some time related parameters
2833 statevector_member_r4%deet = ens%statevector_work%deet
2834 statevector_member_r4%dateOriginList(1) = ens%statevector_work%dateOriginList(stepIndex)
2835 statevector_member_r4%npasList(1) = ens%statevector_work%npasList(stepIndex)
2836 statevector_member_r4%ip2List(1) = ens%statevector_work%ip2List(stepIndex)
2837 ! if it exists, copy over mask from work statevector to member being written
2838 call gsv_copyMask(ens%stateVector_work, stateVector_member_r4)
2839
2840 do memberIndex = 1, ens%numMembers
2841
2842 ! MPI communication: from 1 lat-lon tile per process to 1 ensemble member per process
2843 if (writeFilePE(memberIndex) == 0) then
2844
2845 batchIndex = ceiling(dble(memberIndex + mmpi_nprocs - 1)/dble(mmpi_nprocs))
2846
2847 do kIndexBeg = 1, numK, numLevelsToSend
2848 kIndexEnd = min(numK,kIndexBeg+numLevelsToSend-1)
2849 numLevelsToSend2 = kIndexEnd - kIndexBeg + 1
2850
2851 if ( ens%dataKind == 8 ) then
2852 !$OMP PARALLEL DO PRIVATE(kCount,memberIndex2,yourid)
2853 do kCount = 1, numLevelsToSend2
2854 do memberIndex2 = 1+(batchIndex-1)*mmpi_nprocs, min(ens%numMembers, batchIndex*mmpi_nprocs)
2855 yourid = writeFilePE(memberIndex2)
2856 gd_send_r4(1:lonPerPE,1:latPerPE,kCount,yourid+1) = &
2857 real(ens%allLev_r8(kCount+kIndexBeg-1)%onelevel(memberIndex2,stepIndex,:,:),4)
2858 end do
2859 end do
2860 !$OMP END PARALLEL DO
2861 else
2862 !$OMP PARALLEL DO PRIVATE(kCount,memberIndex2,yourid)
2863 do kCount = 1, numLevelsToSend2
2864 do memberIndex2 = 1+(batchIndex-1)*mmpi_nprocs, min(ens%numMembers, batchIndex*mmpi_nprocs)
2865 yourid = writeFilePE(memberIndex2)
2866 gd_send_r4(1:lonPerPE,1:latPerPE,kCount,yourid+1) = &
2867 ens%allLev_r4(kCount+kIndexBeg-1)%onelevel(memberIndex2,stepIndex,:,:)
2868 end do
2869 end do
2870 !$OMP END PARALLEL DO
2871 end if
2872
2873 nsize = lonPerPEmax * latPerPEmax * numLevelsToSend2
2874 if (mmpi_nprocs > 1) then
2875 call rpn_comm_alltoall(gd_send_r4(:,:,1:numLevelsToSend2,:),nsize,"mpi_real4", &
2876 gd_recv_r4(:,:,1:numLevelsToSend2,:),nsize,"mpi_real4","GRID",ierr)
2877 else
2878 gd_recv_r4(:,:,1:numLevelsToSend2,1) = gd_send_r4(:,:,1:numLevelsToSend2,1)
2879 end if
2880
2881 call gsv_getField(statevector_member_r4,ptr3d_r4)
2882 !$OMP PARALLEL DO PRIVATE(youridy,youridx,yourid)
2883 do youridy = 0, (mmpi_npey-1)
2884 do youridx = 0, (mmpi_npex-1)
2885 yourid = youridx + youridy*mmpi_npex
2886 ptr3d_r4(ens%statevector_work%allLonBeg(youridx+1):ens%statevector_work%allLonEnd(youridx+1), &
2887 ens%statevector_work%allLatBeg(youridy+1):ens%statevector_work%allLatEnd(youridy+1), kIndexBeg:kIndexEnd) = &
2888 gd_recv_r4(1:ens%statevector_work%allLonPerPE(youridx+1), &
2889 1:ens%statevector_work%allLatPerPE(youridy+1), 1:numLevelsToSend2, yourid+1)
2890
2891 end do
2892 end do
2893 !$OMP END PARALLEL DO
2894
2895 end do ! kIndexBeg
2896
2897 end if ! MPI communication
2898
2899
2900 ! Write statevector to file
2901 if (mmpi_myid == writeFilePE(memberIndex)) then
2902
2903 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2904
2905 if ( typvar == 'A' .or. typvar == 'R' ) then
2906 if ( typvar == 'R' ) then
2907 call fln_ensAnlFileName( ensFileName, ensPathName, tim_getDateStamp(), &
2908 memberIndex_opt=memberIndex, &
2909 ensFileNamePrefix_opt=ensFileNamePrefix, &
2910 ensFileNameSuffix_opt='inc' )
2911 else
2912 call fln_ensAnlFileName( ensFileName, ensPathName, tim_getDateStamp(), &
2913 memberIndex_opt=memberIndex, &
2914 ensFileNamePrefix_opt=ensFileNamePrefix )
2915 end if
2916 ensFileExtLength = 4
2917 else
2918 call fln_ensFileName( ensFileName, ensPathName, memberIndex_opt=memberIndex, &
2919 ensFileNamePrefix_opt=ensFileNamePrefix, &
2920 shouldExist_opt=.false., ensembleFileExtLength_opt=ensFileExtLength, &
2921 fileMemberIndex1_opt=ens%fileMemberIndex1 )
2922 end if
2923
2924 ! Determine if ensemble is full fields (if yes, will be converted from K to C)
2925 if (present(containsFullField_opt)) then
2926 containsFullField = containsFullField_opt
2927 else
2928 containsFullField = (.not. ens%meanIsRemoved)
2929 end if
2930
2931 etiketStr = etiket
2932
2933 if (present(etiketAppendMemberNumber_opt)) then
2934 if (etiketAppendMemberNumber_opt .and. etiketStr /= 'UNDEFINED') then
2935 write(ensFileExtLengthStr,"(I1)") ensFileExtLength
2936 write(memberIndexStr,'(I0.' // trim(ensFileExtLengthStr) // ')') memberIndex
2937 ! 12 is the maximum length of an etiket for RPN fstd files
2938 maximumBaseEtiketLength = 12 - ensFileExtLength
2939 if ( len(trim(etiketStr)) >= maximumBaseEtiketLength ) then
2940 etiketStr = etiketStr(1:maximumBaseEtiketLength) // trim(memberIndexStr)
2941 else
2942 etiketStr = trim(etiketStr) // trim(memberIndexStr)
2943 end if
2944 end if
2945 end if
2946
2947 ! The routine 'gio_writeToFile' ignores the supplied
2948 ! argument for the etiket, here 'etiketStr', if
2949 ! 'statevector_member_r4%etiket' is different from
2950 ! 'UNDEFINED'. So we must define it explicitely in the
2951 ! 'statevector_member_r4'.
2952 statevector_member_r4%etiket = etiketStr
2953
2954 call gio_writeToFile( statevector_member_r4, ensFileName, etiketStr, ip3_opt = ip3, &
2955 typvar_opt = typvar, numBits_opt = numBits_opt, &
2956 containsFullField_opt = containsFullField )
2957
2958 end if ! locally written one member
2959
2960 end do ! memberIndex
2961
2962 ! deallocate the needed statevector objects
2963 call gsv_deallocate(statevector_member_r4)
2964
2965 end do ! time
2966
2967 deallocate(varNamesInEns)
2968 deallocate(gd_send_r4)
2969 deallocate(gd_recv_r4)
2970 deallocate(datestamplist)
2971
2972 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2973 write(*,*) 'ens_writeEnsemble: finished communicating and writing ensemble members...'
2974
2975 end subroutine ens_writeEnsemble
2976
2977 !--------------------------------------------------------------------------
2978 ! ens_applyMaskLAM
2979 !--------------------------------------------------------------------------
2980 subroutine ens_applyMaskLAM(ensIncrement, stateVectorAnalIncMask)
2981 !:Purpose: To apply a mask to an ensemble state vector for LAM grid
2982 !
2983 implicit none
2984
2985 ! Arguments
2986 type(struct_ens), intent(inout) :: ensIncrement
2987 type(struct_gsv), intent(in) :: stateVectorAnalIncMask
2988
2989 ! Locals
2990 real(4), pointer :: increment_ptr(:,:,:,:)
2991 real(pre_incrReal), pointer :: analIncMask_ptr(:,:,:)
2992 integer :: nEns, numVarLev, myLonBeg, myLonEnd, myLatBeg, myLatEnd
2993 integer :: varLevIndex, lonIndex, latIndex, stepIndex, memberIndex
2994
2995 write(*,*) 'ens_applyMaskLAM: starting'
2996
2997 if (.not.(ens_isAllocated(ensIncrement).and.(gsv_isAllocated(stateVectorAnalIncMask)))) then
2998 call utl_abort('epp_applyMaskLAM: increment and mask must be avaliable.')
2999 end if
3000
3001 call gsv_getField(stateVectorAnalIncMask, analIncMask_ptr)
3002
3003 nEns = ens_getNumMembers(ensIncrement)
3004 numVarLev = ens_getNumK(ensIncrement)
3005 call ens_getLatLonBounds(ensIncrement, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
3006 do varLevIndex = 1, numVarLev
3007 increment_ptr => ens_getOneLev_r4(ensIncrement,varLevIndex)
3008 !$OMP PARALLEL DO PRIVATE (stepIndex,latIndex,lonIndex,memberIndex)
3009 do latIndex = myLatBeg, myLatEnd
3010 do lonIndex = myLonBeg, myLonEnd
3011 do stepIndex = 1, tim_nstepobsinc
3012 do memberIndex = 1, nEns
3013 increment_ptr(memberIndex,stepIndex,lonIndex,latIndex) = &
3014 increment_ptr(memberIndex,stepIndex,lonIndex,latIndex) * &
3015 analIncMask_ptr(lonIndex,latIndex,1)
3016 end do
3017 end do
3018 end do
3019 end do
3020 !$OMP END PARALLEL DO
3021 end do
3022 write(*,*) 'ens_applyMaskLAM: finished to mask each member of increments'
3023
3024 end subroutine ens_applyMaskLAM
3025
3026end module ensembleStateVector_mod