1module menetrierDiag_mod
2 ! MODULE menetrierDiag_mod (prefix='bmd' category='1. High-level functionality')
3 !
4 !:Purpose: To compute optimal localization radii according to the theory
5 ! developed by Benjamin Menetrier (Meteo-France) and reported
6 ! in Menetrier, Michel, Montmerle and Berre, 2015, Parts 1 and 2.
7 !
8 use earthConstants_mod
9 use utilities_mod
10 use localizationFunction_mod
11 use varNameList_mod
12 use horizontalCoord_mod
13 use gridStatevector_mod
14 use ensembleStatevector_mod
15 use timeCoord_mod
16 use midasMpi_mod
17 implicit none
18 save
19 private
20
21 ! Public Subroutines
22 public :: bmd_setup, bmd_localizationRadii
23
24 real(8), pointer :: pressureProfile_M(:), pressureProfile_T(:)
25
26 type(struct_hco), pointer :: hco_ens ! Ensemble horizontal grid parameters
27
28 integer :: nens, ni, nj, nLevEns_M, nLevEns_T, nkgdimEns
29 integer :: nvar3d, nvar2d, nWaveBand
30
31 integer, allocatable :: varLevOffset(:)
32
33 character(len=4), allocatable :: nomvar3d(:), nomvar2d(:)
34
35 logical :: global
36
37 logical :: initialized = .false.
38
39 ! Namelist variables:
40 integer :: strideForHLoc
41 integer :: strideForVloc
42 integer :: horizPadding
43 logical :: hLoc
44 logical :: vLoc
45
46contains
47
48 !--------------------------------------------------------------------------
49 ! bmd_setup
50 !--------------------------------------------------------------------------
51 subroutine bmd_setup(statevector_template, hco_core_in, nens_in, pressureProfile_M_in, &
52 pressureProfile_T_in, nWaveBand_in)
53 implicit none
54
55 ! Arguments:
56 type(struct_gsv), intent(in) :: statevector_template
57 type(struct_hco), pointer, intent(in) :: hco_core_in
58 integer, intent(in) :: nens_in
59 integer, intent(in) :: nWaveBand_in
60 real(8), pointer, intent(inout) :: pressureProfile_M_in(:)
61 real(8), pointer, intent(inout) :: pressureProfile_T_in(:)
62
63 ! Locals:
64 integer :: nulnam, ierr, fclos, fnom
65 integer :: nVar, varNameIndex, var2dIndex, var3dIndex
66 character(len=4), pointer :: varNamesList(:)
67
68 NAMELIST /NAMLOCALIZATIONRADII/strideForHLoc,strideForVloc,hLoc,vLoc,horizPadding
69
70 !
71 !- 1. Input parameters
72 !
73 hco_ens => hco_core_in
74 nens = nens_in
75 ni = hco_ens%ni
76 nj = hco_ens%nj
77 nLevEns_M = gsv_getNumLev(statevector_template,'MM') !nLevEns_M_in
78 nLevEns_T = gsv_getNumLev(statevector_template,'TH') !nLevEns_T_in
79 nkgdimEns = statevector_template%nk
80 pressureProfile_M => pressureProfile_M_in
81 pressureProfile_T => pressureProfile_T_in
82 nWaveBand = nWaveBand_in
83 global = hco_ens%global
84
85 nullify(varNamesList)
86 call gsv_varNamesList(varNamesList, statevector_template)
87
88 nVar = size(varNamesList)
89 allocate(varLevOffset(nVar))
90 nVar3d = 0
91 nVar2d = 0
92 do varNameIndex = 1, size(varNamesList)
93 varLevOffset(varNameIndex) = gsv_getOffsetFromVarName(statevector_template,varNamesList(varNameIndex))
94 if (vnl_varLevelFromVarname(varNamesList(varNameIndex)) == 'SF' ) then
95 nVar2d = nVar2d + 1
96 else
97 nVar3d = nVar3d + 1
98 end if
99 end do
100
101 allocate(nomvar3d(nvar3d))
102 allocate(nomvar2d(nvar2d))
103
104 var2dIndex = 0
105 var3dIndex = 0
106 do varNameIndex = 1, size(varNamesList)
107 if (vnl_varLevelFromVarname(varNamesList(varNameIndex)) == 'SF' ) then
108 var2dIndex = var2dIndex + 1
109 nomvar2d(var2dIndex) = varNamesList(varNameIndex)
110 else
111 var3dIndex = var3dIndex + 1
112 nomvar3d(var3dIndex) = varNamesList(varNameIndex)
113 end if
114 end do
115
116 !
117 !- 2. Read Namelist
118 !
119 hLoc = .true.
120 vLoc = .true.
121 strideForHLoc = 100 ! Horizontal correlations will be computed every "stride" gridpoint in x and y
122 strideForVLoc = 50 ! Vertical correlations will be computed every "stride" gridpoint in x and y
123 horizPadding = 0 ! Number of grid point to discard along the horizontal edges (only for LAM)
124
125 nulnam = 0
126 ierr = fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
127 read(nulnam,nml=NAMLOCALIZATIONRADII)
128 write(*,nml=NAMLOCALIZATIONRADII)
129 ierr = fclos(nulnam)
130
131 !
132 !- 3. Ending
133 !
134 initialized = .true.
135
136 end subroutine bmd_setup
137
138 !--------------------------------------------------------------------------
139 ! bmd_localizationRadii
140 !--------------------------------------------------------------------------
141 subroutine bmd_localizationRadii(ensPerts,waveBandIndex_opt)
142 implicit none
143
144 ! Arguments:
145 type(struct_ens), intent(inout) :: ensPerts
146 integer,optional, intent(in) :: waveBandIndex_opt
147
148 !
149 !- Estimate the horionzontal and vertical localization radii
150 !
151 if ( hLoc ) then
152 call calcHorizLocalizationRadii(ensPerts, strideForHLoc, & ! IN
153 waveBandIndex_opt=waveBandIndex_opt) ! IN
154 end if
155 if ( vLoc ) then
156 call calcVertLocalizationRadii(ensPerts, strideForVloc, & ! IN
157 waveBandIndex_opt=waveBandIndex_opt) ! IN
158 end if
159
160 end subroutine bmd_localizationRadii
161
162 !--------------------------------------------------------------------------
163 ! CALCHORIZLOCALIZATIONRADII
164 !--------------------------------------------------------------------------
165 subroutine calcHorizLocalizationRadii(ensPerts,stride,waveBandIndex_opt)
166 implicit none
167
168 ! Arguments:
169 type(struct_ens), intent(inout) :: ensPerts
170 integer, intent(in) :: stride
171 integer, optional, intent(in) :: waveBandIndex_opt
172
173 ! Locals:
174 type(struct_gsv) :: statevector_ensStdDev
175 type(struct_gsv) :: statevector_ensStdDev_tiles
176 type(struct_gsv) :: statevector_oneMemberTiles
177 type(struct_gsv) :: statevector_oneMember(nens)
178 real(8), pointer :: ensStdDev(:,:,:)
179 real(4), pointer :: ptr3d_r4(:,:,:)
180 real(4), allocatable :: ensPert_local(:,:,:)
181 real(8), allocatable :: meanCorrel(:,:)
182 real(8), allocatable :: meanCorrelSquare(:,:)
183 real(8), allocatable :: meanVarianceProduct(:,:)
184 real(8), allocatable :: meanCovarianceSquare(:,:)
185 real(8), allocatable :: meanFourthMoment(:,:)
186 real(8), allocatable :: meanCorrel_local(:,:)
187 real(8), allocatable :: meanCorrelSquare_local(:,:)
188 real(8), allocatable :: meanVarianceProduct_local(:,:)
189 real(8), allocatable :: meanCovarianceSquare_local(:,:)
190 real(8), allocatable :: meanFourthMoment_local(:,:)
191 real(8), allocatable :: localizationFunctions(:,:,:) ! Eq. 19-21 in MMMB 2015 Part 2
192 real(8), allocatable :: localizationRadii(:,:)
193 real(8), allocatable :: distanceBinThresholds(:) ! Maximum distance for each distance-bin
194 real(8), allocatable :: distanceBinMean(:) ! Mean distance for each distance-bin
195 real(8), allocatable :: distanceBinWeight(:) ! Weight given to each bin in the curve fitting step
196 real(8), allocatable :: gridPointWeight(:,:,:) ! Weight given to grid point in the statistic computation
197 real(8), allocatable :: sumWeight(:,:) ! Sample size for each distance-bin
198 real(8), allocatable :: sumWeight_local(:,:)
199 real(8), pointer :: PressureProfile(:)
200 logical, allocatable :: gridPointAlreadyUsed(:,:)
201 real(8) :: dnens, correlation, covariance, fourthMoment, distance, maxDistance, weight
202 real(8) :: t1, t2, t3, rmse
203 integer :: i, j, k, f, ens, bin, numbins, numFunctions, nSize
204 integer :: iref, jref, ier
205 integer :: nLevEns, jvar, mykBeg, mykEnd
206 character(len=128) :: outfilename
207 character(len=2) :: wbnum
208 character(len=4), pointer :: varNamesList(:)
209
210 !
211 !- 1. Setup
212 !
213 call ens_copyEnsStdDev(ensPerts, statevector_ensStdDev_tiles)
214
215 nullify(varNamesList)
216 call ens_varNamesList(varNamesList,ensPerts)
217 call gsv_allocate(statevector_ensStdDev, ens_getNumStep(ensPerts), &
218 ens_getHco(ensPerts), ens_getVco(ensPerts), varNames_opt=varNamesList, &
219 datestamp_opt=tim_getDatestamp(), mpi_local_opt=.true., &
220 mpi_distribution_opt='VarsLevs', dataKind_opt=8 )
221 call gsv_transposeTilesToVarsLevs(statevector_ensStdDev_tiles, statevector_ensStdDev)
222 call gsv_getField(statevector_ensStdDev,ensStdDev)
223
224 call gsv_deallocate(statevector_ensStdDev_tiles)
225
226 mykBeg = statevector_ensStdDev%mykBeg
227 mykEnd = statevector_ensStdDev%mykEnd
228
229 numFunctions = 3
230
231 if ( global ) then
232 numBins = ni/4 ! 1/4 of the Earth
233 if ( horizPadding /= 0 ) then
234 write(*,*)
235 write(*,*) 'WARNING: horizPadding /= 0. Force it to zero since we are in global mode.'
236 horizPadding = 0
237 end if
238 else
239 numBins = ni-(2*horizPadding)
240 if ( horizPadding == 0 ) then
241 write(*,*)
242 write(*,*) 'WARNING: horizPadding == 0. The rim and blending zone WILL HAVE an impact on the results.'
243 end if
244 end if
245
246 allocate(meanCorrelSquare(numBins,nkgdimEns))
247 allocate(meanCorrel(numBins,nkgdimEns))
248 allocate(meanVarianceProduct(numBins,nkgdimEns))
249 allocate(meanCovarianceSquare(numBins,nkgdimEns))
250 allocate(meanFourthMoment(numBins,nkgdimEns))
251 allocate(sumWeight(numBins,nkgdimEns))
252
253 allocate(meanCorrelSquare_local(numBins,nkgdimEns))
254 allocate(meanCorrel_local(numBins,nkgdimEns))
255 allocate(meanVarianceProduct_local(numBins,nkgdimEns))
256 allocate(meanCovarianceSquare_local(numBins,nkgdimEns))
257 allocate(meanFourthMoment_local(numBins,nkgdimEns))
258 allocate(sumWeight_local(numBins,nkgdimEns))
259
260 allocate(gridPointWeight(ni,nj,nkgdimEns))
261
262 allocate(distanceBinThresholds(numBins))
263
264 ! Assign the (upper) threshold to each separation-distance-bin
265 write(*,*)
266 write(*,*) 'Separation distance bin'
267 do bin = 1, numbins
268 distanceBinThresholds(bin) = calcDistance(hco_ens%lat(nj/2),hco_ens%lon(1+horizPadding),hco_ens%lat(nj/2),hco_ens%lon(bin+horizPadding))
269 write(*,*) bin, hco_ens%lat(nj/2),hco_ens%lon(1+horizPadding),hco_ens%lon(bin+horizPadding), distanceBinThresholds(bin)/1000.d0
270 end do
271
272 maxDistance=distanceBinThresholds(numBins)
273
274 dnens = 1.0d0/dble(nens-1)
275
276 ! Grid point Weight
277 write(*,*)
278 write(*,*) 'Grid point Weight'
279 do j = 1, nj
280 gridPointWeight(:,j,:) = cos(hco_ens%lat(j))
281 write(*,*) j, hco_ens%lat(j), cos(hco_ens%lat(j))
282 end do
283
284 !
285 !- 2. Estimation of localization functions
286 !
287
288 !- 2.1 Computation of various statistics for different separation distances
289 meanCorrelSquare_local(:,:) = 0.d0
290 meanCorrel_local(:,:) = 0.d0
291 meanCovarianceSquare_local(:,:) = 0.d0
292 meanVarianceProduct_local(:,:) = 0.d0
293 meanFourthMoment_local(:,:) = 0.d0
294 sumWeight_local(:,:) = 0.d0
295
296 allocate(ensPert_local(nens,ni,nj))
297 allocate(gridPointAlreadyUsed(ni,nj))
298
299 call gsv_allocate(statevector_oneMemberTiles, ens_getNumStep(ensPerts), &
300 ens_getHco(ensPerts), ens_getVco(ensPerts), varNames_opt=varNamesList, &
301 datestamp_opt=tim_getDatestamp(), mpi_local_opt=.true., &
302 mpi_distribution_opt='Tiles', dataKind_opt=4 )
303
304 do ens = 1, nens
305 call gsv_allocate(statevector_oneMember(ens), ens_getNumStep(ensPerts), &
306 ens_getHco(ensPerts), ens_getVco(ensPerts), varNames_opt=varNamesList, &
307 datestamp_opt=tim_getDatestamp(), mpi_local_opt=.true., &
308 mpi_distribution_opt='VarsLevs', dataKind_opt=4 )
309 call ens_copyMember(ensPerts, statevector_oneMemberTiles, ens)
310 call gsv_transposeTilesToVarsLevs(statevector_oneMemberTiles, statevector_oneMember(ens))
311 end do
312
313 call gsv_deallocate(statevector_oneMemberTiles)
314
315 !$OMP PARALLEL DO PRIVATE (ptr3d_r4,k,iref,jref,j,i,ens,correlation,covariance,fourthMoment,distance,bin,weight,ensPert_local,gridPointAlreadyUsed)
316 do k = mykBeg, mykEnd
317 write(*,*) 'Computing distance-bin statistics for ensemble level: ', k
318
319 !- Select data needed to speed up the process (ensemble member index must come first in ensPert_Local
320 ! because ensemble member is the last loop index below)
321 do ens = 1, nens
322 call gsv_getField(statevector_oneMember(ens),ptr3d_r4)
323 do j = 1, nj
324 do i = 1, ni
325 ensPert_local(ens,i,j) = ptr3d_r4(i,j,k)
326 end do
327 end do
328 end do
329
330 gridPointAlreadyUsed(:,:) = .false.
331
332 do jref = nint(stride/2.0)+horizPadding, nj-horizPadding, stride ! Pick every stride point to save cost.
333 do iref = nint(stride/2.0)+horizPadding, ni-horizPadding, stride ! Pick every stride point to save cost.
334
335 if (k == 1) then
336 write(*,*) 'grid point info', iref, jref
337 end if
338
339 do j = 1+horizPadding, nj-horizPadding
340 do i = 1+horizPadding, ni-horizPadding
341
342 if ( gridPointAlreadyUsed(i,j) ) cycle ! prevent using the same pair of points more than once
343
344 distance=calcDistance(hco_ens%lat(jref),hco_ens%lon(iref),hco_ens%lat(j),hco_ens%lon(i))
345 if (distance <= maxDistance .and. gridPointWeight(i,j,k) > 0.d0) then
346 covariance = 0.d0
347 fourthMoment = 0.d0
348 do ens = 1, nens
349 covariance = covariance + &
350 ensPert_local(ens,i,j) * ensPert_local(ens,iref,jref)
351 fourthMoment = fourthMoment + &
352 (ensPert_local(ens,i,j) * ensPert_local(ens,iref,jref))**2
353 end do
354 covariance = covariance * dnens
355 fourthMoment = fourthMoment / real(nens,8)
356 if ( ensStdDev(i,j,k) > 0.d0 .and. ensStdDev(iref,jref,k) > 0.d0 ) then
357 correlation = covariance / (ensStdDev(i,j,k)*ensStdDev(iref,jref,k))
358 else
359 correlation = 0.d0
360 end if
361
362 bin=findBinIndex(distance,distanceBinThresholds,numBins)
363
364 weight = sqrt(gridPointWeight(iref,jref,k)) * sqrt(gridPointWeight(i,j,k))
365
366 sumWeight_local(bin,k) = sumWeight_local(bin,k) + weight
367
368 meanCorrel_local(bin,k) = meanCorrel_local(bin,k) + &
369 correlation * weight
370 meanCorrelSquare_local(bin,k) = meanCorrelSquare_local(bin,k) + &
371 correlation**2 * weight
372 meanCovarianceSquare_local(bin,k) = meanCovarianceSquare_local(bin,k) + &
373 covariance**2 * weight
374 meanVarianceProduct_local(bin,k) = meanVarianceProduct_local(bin,k) + &
375 ensStdDev(i,j,k)**2 * ensStdDev(iref,jref,k)**2 * weight
376 meanFourthMoment_local(bin,k) = meanFourthMoment_local(bin,k) + &
377 fourthMoment * weight
378 end if
379 end do
380 end do
381
382 ! From now on, omit the current reference point
383 gridPointAlreadyUsed(iref,jref) = .true.
384
385 end do ! iref
386 end do ! jref
387
388 end do ! nkgdimEns
389 !$OMP END PARALLEL DO
390
391 deallocate(ensPert_local)
392 deallocate(gridPointAlreadyUsed)
393 do ens = 1, nens
394 call gsv_deallocate(statevector_oneMember(ens))
395 end do
396
397 !- 2.2 Gather the all the info in processor 0
398 nSize = nkgdimEns * numbins
399 call rpn_comm_reduce(sumWeight_local ,sumWeight ,nSize, &
400 "mpi_double_precision","mpi_sum",0,"GRID",ier)
401 call rpn_comm_reduce(meanCorrel_local ,meanCorrel ,nSize, &
402 "mpi_double_precision","mpi_sum",0,"GRID",ier)
403 call rpn_comm_reduce(meanCorrelSquare_local ,meanCorrelSquare ,nSize, &
404 "mpi_double_precision","mpi_sum",0,"GRID",ier)
405 call rpn_comm_reduce(meanVarianceProduct_local ,meanVarianceProduct ,nSize, &
406 "mpi_double_precision","mpi_sum",0,"GRID",ier)
407 call rpn_comm_reduce(meanFourthMoment_local ,meanFourthMoment ,nSize, &
408 "mpi_double_precision","mpi_sum",0,"GRID",ier)
409 call rpn_comm_reduce(meanCovarianceSquare_local,meanCovarianceSquare,nSize, &
410 "mpi_double_precision","mpi_sum",0,"GRID",ier)
411
412 deallocate(sumWeight_local)
413 deallocate(meanCorrel_local)
414 deallocate(meanCorrelSquare_local)
415 deallocate(meanVarianceProduct_local)
416 deallocate(meanFourthMoment_local)
417 deallocate(meanCovarianceSquare_local)
418
419 if (mmpi_myid == 0) then
420 !- 2.3 Computation of the localization functions
421 allocate(localizationFunctions(numFunctions,numBins,nkgdimEns))
422
423 t1=dble((nens-1)**2)/dble(nens*(nens-3))
424 t2=dble(nens)/dble((nens-2)*(nens-3))
425 t3=dble(nens-1)/dble(nens*(nens-2)*(nens-3))
426 !$OMP PARALLEL DO PRIVATE (k,bin)
427 do k = 1, nkgdimEns
428 do bin = 1, numbins
429
430 meanCorrel(bin,k) = meanCorrel(bin,k) / sumWeight(bin,k)
431 meanCorrelSquare(bin,k) = meanCorrelSquare(bin,k) / sumWeight(bin,k)
432 meanCovarianceSquare(bin,k) = meanCovarianceSquare(bin,k) / sumWeight(bin,k)
433 meanVarianceProduct(bin,k) = meanVarianceProduct(bin,k) / sumWeight(bin,k)
434 meanFourthMoment(bin,k) = meanFourthMoment(bin,k) / sumWeight(bin,k)
435
436 if ( meanCovarianceSquare(bin,k) /= 0.d0 ) then
437 ! Form 1: General formulation (Eq. 19 in MMMB 2015 Part 2)
438 localizationFunctions(1,bin,k) = t1 - t2*meanFourthMoment(bin,k)/meanCovarianceSquare(bin,k) + &
439 t3*meanVarianceProduct(bin,k)/meanCovarianceSquare(bin,k)
440 ! Form 2: Gaussian sample distribution (Eq. 20 in MMMB 2015 Part 2)
441 localizationFunctions(2,bin,k) = dble(nens-1)/dble((nens+1)*(nens-2)) * &
442 (dble(nens-1)-meanVarianceProduct(bin,k)/meanCovarianceSquare(bin,k))
443 else
444 write(*,*) ' !!! Warning !!! meanCovarianceSquare = 0 in bin, level = ', bin, k
445 localizationFunctions(1,bin,k) = 0.d0
446 localizationFunctions(2,bin,k) = 0.d0
447 end if
448 ! Form 3: Gaussian sample distribution and correlation-based formulation (Eq. 21 in MMMB 2015 Part 2)
449 if ( meanCorrelSquare(bin,k) /= 0.d0 ) then
450 localizationFunctions(3,bin,k) = dble(nens-1)/dble((nens+1)*(nens-2)) * &
451 (dble(nens-1)-1.d0/meanCorrelSquare(bin,k))
452 else
453 write(*,*) ' !!! Warning !!! meanCorrelSquare = 0 in bin, level = ', bin, k
454 localizationFunctions(3,bin,k) = 0.d0
455 end if
456 end do
457 end do
458 !$OMP END PARALLEL DO
459
460 !
461 !- 3. Estimation of localization radii (curve fitting)
462 !
463 allocate(localizationRadii(numFunctions,nkgdimEns))
464 allocate(distanceBinMean(numBins))
465 allocate(distanceBinWeight(numBins))
466
467 call lfn_setup('FifthOrder') ! IN
468
469 localizationRadii(:,:) = 2000.d0*1000.d0 ! First Guess (meter)
470 distanceBinWeight(:) = 1.d0 ! Even weight
471 do bin = 1, numBins
472 if (bin == 1) then
473 distanceBinMean(bin) = distanceBinThresholds(bin) ! = 0 m
474 else
475 distanceBinMean(bin) = 0.5d0*(distanceBinThresholds(bin)+distanceBinThresholds(bin-1))
476 end if
477 end do
478
479 do f = 1, numFunctions
480 write(*,*)
481 write(*,*) 'Localization Function : ', f
482 do k = 1, nkgdimEns
483 write(*,*) ' ----- EnsLev : ', k
484 call lfn_lengthscale( localizationRadii(f,k), & ! INOUT
485 rmse, & ! OUT
486 localizationFunctions(f,:,k), & ! IN
487 distanceBinMean, & ! IN
488 distanceBinWeight, & ! IN
489 numbins ) ! IN
490 end do
491 end do
492
493 !
494 !- 4. Write to file
495 !
496 if ( nWaveBand /= 1 ) then
497 if (.not. present(waveBandIndex_opt)) then
498 write(*,*) 'calcLocalizationRadii: No waveBandIndex was supplied!!!'
499 call utl_abort('calbmatrix_glb')
500 end if
501 write(wbnum,'(I2.2)') waveBandIndex_opt
502 end if
503
504 !- 4.1 Localization functions in txt format (for plotting purposes)
505 do jvar = 1, nvar3d
506 if ( nWaveBand == 1 ) then
507 outfilename = "./horizLocalizationFunctions_"//trim(nomvar3d(jvar))//".txt"
508 else
509 outfilename = "./horizLocalizationFunctions_"//trim(nomvar3d(jvar))//"_"//wbnum//".txt"
510 end if
511 open (unit=99,file=outfilename,action="write",status="new")
512
513 if(vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
514 nLevEns = nLevEns_M
515 else
516 nLevEns = nLevEns_T
517 endif
518 do k=1,nlevEns
519 do bin = 1, numbins
520 write(99,'(I3,2X,I3,2X,F7.1,2X,I7,2X,F6.4,2X,F6.4,2X,F6.4,2X,F6.4,2X,F6.4,2X,E10.3,2X,E10.3,2X,E10.3)') k, bin, &
521 distanceBinThresholds(bin)/1000.d0, nint(sumWeight(bin,varLevOffset(jvar)+k)), &
522 meanCorrel(bin,varLevOffset(jvar)+k), &
523 localizationFunctions(3,bin,varLevOffset(jvar)+k), &
524 localizationFunctions(2,bin,varLevOffset(jvar)+k), &
525 localizationFunctions(1,bin,varLevOffset(jvar)+k), &
526 meanCorrelSquare(bin,varLevOffset(jvar)+k), &
527 meanCovarianceSquare(bin,varLevOffset(jvar)+k), &
528 meanVarianceProduct(bin,varLevOffset(jvar)+k), &
529 meanFourthMoment(bin,varLevOffset(jvar)+k)
530 end do
531 end do
532 close(unit=99)
533 end do
534
535 do jvar = 1, nvar2d
536 k = varLevOffset(nvar3d+1)+jvar
537 if ( nWaveBand == 1 ) then
538 outfilename = "./horizLocalizationFunctions_"//trim(nomvar2d(jvar))//".txt"
539 else
540 outfilename = "./horizLocalizationFunctions_"//trim(nomvar2d(jvar))//"_"//wbnum//".txt"
541 end if
542 open (unit=99,file=outfilename,action="write",status="new")
543 do bin = 1, numbins
544 write(99,'(I3,2X,I3,2X,F7.1,2X,I7,2X,F6.4,2X,F6.4,2X,F6.4,2X,F6.4,2X,F6.4,2X,E10.3,2X,E10.3,2X,E10.3)') 1, bin, &
545 distanceBinThresholds(bin)/1000.d0, nint(sumWeight(bin,k)), &
546 meanCorrel(bin,k), &
547 localizationFunctions(3, bin,k), &
548 localizationFunctions(2, bin,k), &
549 localizationFunctions(1, bin,k), &
550 meanCorrelSquare(bin,k), &
551 meanCovarianceSquare(bin,k), &
552 meanVarianceProduct(bin,k), &
553 meanFourthMoment(bin,k)
554 end do
555 close(unit=99)
556 end do
557
558 !- 4.2 Localization radii in txt format (for plotting purposes)
559 do jvar = 1, nvar3d
560 if ( nWaveBand == 1 ) then
561 outfilename = "./horizLocalizationRadii_"//trim(nomvar3d(jvar))//".txt"
562 else
563 outfilename = "./horizLocalizationRadii_"//trim(nomvar3d(jvar))//"_"//wbnum//".txt"
564 end if
565 open (unit=99,file=outfilename,action="write",status="new")
566
567 if(vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
568 nLevEns = nLevEns_M
569 PressureProfile => pressureProfile_M
570 else
571 nLevEns = nLevEns_T
572 PressureProfile => pressureProfile_T
573 endif
574 do k=1,nlevEns
575 write(99,'(I3,2X,F7.2,2X,F7.1,2X,F7.1,2X,F7.1)') k, PressureProfile(k)/100.d0, &
576 min(localizationRadii(3,varLevOffset(jvar)+k)/1000.d0,99999.9d0), &
577 min(localizationRadii(2,varLevOffset(jvar)+k)/1000.d0,99999.9d0), &
578 min(localizationRadii(1,varLevOffset(jvar)+k)/1000.d0,99999.9d0)
579 end do
580 close(unit=99)
581 end do
582
583 do jvar = 1, nvar2d
584 k = varLevOffset(nvar3d+1)+jvar
585 if ( nWaveBand == 1 ) then
586 outfilename = "./horizLocalizationRadii_"//trim(nomvar2d(jvar))//".txt"
587 else
588 outfilename = "./horizLocalizationRadii_"//trim(nomvar2d(jvar))//"_"//wbnum//".txt"
589 end if
590 open (unit=99,file=outfilename,action="write",status="new")
591 write(99,'(I3,2X,F7.2,2X,F7.1,2X,F7.1,2X,F7.1)') 1, 1010.0, &
592 min(localizationRadii(3,k)/1000.d0,99999.9d0), &
593 min(localizationRadii(2,k)/1000.d0,99999.9d0), &
594 min(localizationRadii(1,k)/1000.d0,99999.9d0)
595 close(unit=99)
596 end do
597
598 deallocate(localizationFunctions)
599 deallocate(localizationRadii)
600 deallocate(distanceBinMean)
601 deallocate(distanceBinWeight)
602
603 end if ! mmpi_myid == 0
604
605 deallocate(meanCorrelSquare)
606 deallocate(meanCorrel)
607 deallocate(meanCovarianceSquare)
608 deallocate(meanVarianceProduct)
609 deallocate(meanFourthMoment)
610 deallocate(distanceBinThresholds)
611 deallocate(sumWeight)
612 deallocate(gridPointWeight)
613
614 write(*,*)
615 write(*,*) 'finished estimating the horizontal localization radii...'
616
617 end subroutine calcHorizLocalizationRadii
618
619 !--------------------------------------------------------------------------
620 ! FINDBININDEX
621 !--------------------------------------------------------------------------
622 function findBinIndex(distance,distanceBinThresholds,numBins) result(binIndex)
623 implicit none
624
625 ! Arguments:
626 integer, intent(in) :: numBins
627 real(8), intent(in) :: distance
628 real(8), intent(in) :: distanceBinThresholds(numBins)
629 ! Result:
630 integer :: binIndex
631
632 ! Locals:
633 integer :: bin
634
635 binIndex = -1
636 do bin = 1, numbins
637 if ( distance <= distanceBinThresholds(bin) ) then
638 binIndex = bin
639 exit
640 end if
641 end do
642
643 if (binIndex == -1) then
644 write(*,*) 'findBinIndex: No match found! ABORTING'
645 call utl_abort('findBinIndex')
646 end if
647
648 end function findBinIndex
649
650 !--------------------------------------------------------------------------
651 ! DISTANCE
652 !--------------------------------------------------------------------------
653 function calcDistance(lat2, lon2, lat1, lon1) result(distanceInM)
654 !:Purpose: To compute the distance between two points on Earth: (lat1,lon1)
655 ! and (lat2,lon2). Calcul utilisant la Formule d'Haversine
656 ! Reference: R.W. Sinnott,'Virtues of Haversine',Sky and Telescope,
657 ! vol.68, no.2, 1984, p.159)
658 implicit none
659
660 ! Arguments:
661 real(8), intent(in) :: lat1
662 real(8), intent(in) :: lon1
663 real(8), intent(in) :: lat2
664 real(8), intent(in) :: lon2
665 ! Result:
666 real(8) :: distanceInM
667
668 ! Locals:
669 real(8) :: dlat, dlon, a, c
670
671 dlon = lon2 - lon1
672 dlat = lat2 - lat1
673
674 a = (sin(dlat/2.d0))**2 + cos(lat1)*cos(lat2)*(sin(dlon/2.d0))**2
675 c = 2.d0 * atan2(sqrt(a),sqrt(1.d0-a))
676 distanceInM = ec_ra * c
677
678 end function calcDistance
679
680 !--------------------------------------------------------------------------
681 ! CALCVERTLOCALIZATIONRADII
682 !--------------------------------------------------------------------------
683 subroutine calcVertLocalizationRadii(ensPerts,stride,waveBandIndex_opt)
684 implicit none
685
686 ! Arguments:
687 type(struct_ens), intent(inout) :: ensPerts
688 integer, intent(in) :: stride
689 integer,optional, intent(in) :: waveBandIndex_opt
690
691 ! Locals:
692 type(struct_gsv) :: statevector_ensStdDev
693 real(8), pointer :: ensStdDev(:,:,:)
694 real(4), pointer :: ptr4d_r4(:,:,:,:)
695 real(4), allocatable :: ensPert_local(:,:)
696 real(8), allocatable :: meanCorrel(:,:)
697 real(8), allocatable :: meanCorrelSquare(:,:)
698 real(8), allocatable :: meanVarianceProduct(:,:)
699 real(8), allocatable :: meanCovarianceSquare(:,:)
700 real(8), allocatable :: meanFourthMoment(:,:)
701 real(8), allocatable :: meanCorrel_local(:,:)
702 real(8), allocatable :: meanCorrelSquare_local(:,:)
703 real(8), allocatable :: meanVarianceProduct_local(:,:)
704 real(8), allocatable :: meanCovarianceSquare_local(:,:)
705 real(8), allocatable :: meanFourthMoment_local(:,:)
706 real(8), allocatable :: localizationFunctions(:,:,:) ! Eq. 19-21 in MMMB 2015 Part 2
707 real(8), allocatable :: localizationRadii(:,:)
708 real(8), allocatable, target :: distanceBinInLnP_T(:,:) ! Distance between each pair of thermo vertical levels in ln(Pressure)
709 real(8), allocatable, target :: distanceBinInLnP_M(:,:) ! Distance between each pair of momentum vertical levels in ln(Pressure)
710 real(8), allocatable :: distanceBinWeight(:) ! Weight given to each bin in the curve fitting step
711 real(8), allocatable :: gridPointWeight(:,:) ! Weight given to grid point in the statistic computation
712 real(8), allocatable :: sumWeight(:,:) ! Sample size for each distance-bin
713 real(8), allocatable :: sumWeight_local(:,:)
714 real(8), pointer :: PressureProfile(:)
715 real(8), pointer :: distanceBinInLnP(:,:)
716 real(8) :: dnens, correlation, covariance, fourthMoment, weight
717 real(8) :: t1, t2, t3, rmse
718 integer :: k, k2, kens, f, ens, bin, numbins, numFunctions
719 integer :: iref, jref
720 integer :: nLevEns, nLevStart, nLevEnd, jvar
721 integer :: myLonBeg, myLonEnd, myLatBeg, myLatEnd, nSize, ier
722 character(len=128) :: outfilename
723 character(len=2) :: wbnum
724
725 !
726 !- 1. Setup
727 !
728 call ens_copyEnsStdDev(ensPerts, statevector_ensStdDev)
729 call gsv_getField(statevector_ensStdDev,ensStdDev)
730
731 numFunctions = 3
732
733 numBins=max(nLevEns_M,nLevEns_T)
734
735 call ens_getLatLonBounds(ensPerts, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
736
737 allocate(meanCorrelSquare(numBins,nkgdimEns))
738 allocate(meanCorrel(numBins,nkgdimEns))
739 allocate(meanVarianceProduct(numBins,nkgdimEns))
740 allocate(meanCovarianceSquare(numBins,nkgdimEns))
741 allocate(meanFourthMoment(numBins,nkgdimEns))
742 allocate(sumWeight(numBins,nkgdimEns))
743
744 allocate(meanCorrelSquare_local(numBins,nkgdimEns))
745 allocate(meanCorrel_local(numBins,nkgdimEns))
746 allocate(meanVarianceProduct_local(numBins,nkgdimEns))
747 allocate(meanCovarianceSquare_local(numBins,nkgdimEns))
748 allocate(meanFourthMoment_local(numBins,nkgdimEns))
749 allocate(sumWeight_local(numBins,nkgdimEns))
750
751 allocate(gridPointWeight(ni,nj))
752
753 allocate(distanceBinInLnP_M(nLevEns_M,nLevEns_M))
754 allocate(distanceBinInLnP_T(nLevEns_T,nLevEns_T))
755
756 ! Compute the separation-distance in ln(p) between vertical levels
757 do k = 1, nLevEns_M
758 do k2 = 1, nLevEns_M
759 distanceBinInLnP_M(k,k2) = abs(log(pressureProfile_M(k))-log(pressureProfile_M(k2)))
760 end do
761 end do
762 do k = 1, nLevEns_T
763 do k2 = 1, nLevEns_T
764 distanceBinInLnP_T(k,k2) = abs(log(pressureProfile_T(k))-log(pressureProfile_T(k2)))
765 end do
766 end do
767
768 dnens = 1.0d0/dble(nens-1)
769
770 ! Grid point Weight
771 do jref = 1, nj
772 gridPointWeight(:,jref) = cos(hco_ens%lat(jref))
773 end do
774
775 !
776 !- 2. Estimation of localization functions
777 !
778
779 !- 2.1 Computation of various statistics for different separation distances
780 meanCorrelSquare_local(:,:) = 0.d0
781 meanCorrel_local(:,:) = 0.d0
782 meanCovarianceSquare_local(:,:) = 0.d0
783 meanVarianceProduct_local(:,:) = 0.d0
784 meanFourthMoment_local(:,:) = 0.d0
785 sumWeight_local(:,:) = 0.d0
786
787 allocate(ensPert_local(nens,nkgdimEns))
788
789 do jref = nint(stride/2.0)+horizPadding, nj-horizPadding, stride ! Pick every stride point to save cost.
790 do iref = nint(stride/2.0)+horizPadding, ni-horizPadding, stride ! Pick every stride point to save cost.
791
792 if (iref < myLonBeg .or. iref > myLonEnd .or. &
793 jref < myLatBeg .or. jref > myLatEnd ) cycle
794
795 !- Select data needed to speed up the process (ensemble member index must come first in ensPert_Local
796 ! because ensemble member is the last loop index below)
797 do ens = 1, nens
798 do k = 1, nkgdimEns
799 ptr4d_r4 => ens_getOneLev_r4(ensPerts,k)
800 ensPert_local(ens,k) = ptr4d_r4(ens,1,iref,jref)
801 end do
802 end do
803
804 ! Loop on all 3D variables
805 do jvar = 1, nvar3d
806
807 if (vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
808 nLevEns = nLevEns_M
809 else
810 nLevEns = nLevEns_T
811 endif
812 nLevStart = varLevOffset(jvar)+ 1
813 nLevEnd = varLevOffset(jvar)+ nLevEns
814
815 !$OMP PARALLEL DO PRIVATE (k,k2,ens,correlation,covariance,fourthMoment,bin,weight)
816 do k = nLevStart, nLevEnd
817 do k2 = nLevStart, nLevEnd
818
819 covariance = 0.d0
820 fourthMoment = 0.d0
821 do ens = 1, nens
822 covariance = covariance + &
823 ensPert_local(ens,k2) * ensPert_local(ens,k)
824 fourthMoment = fourthMoment + &
825 (ensPert_local(ens,k2) * ensPert_local(ens,k))**2
826 end do
827 covariance = covariance * dnens
828 fourthMoment = fourthMoment / real(nens,8)
829 if ( ensStdDev(iref,jref,k2) > 0.d0 .and. ensStdDev(iref,jref,k) > 0.d0 ) then
830 correlation = covariance / (ensStdDev(iref,jref,k2)*ensStdDev(iref,jref,k))
831 else
832 correlation = 0.d0
833 end if
834
835 bin=k2-nLevStart+1
836
837 weight = gridPointWeight(iref,jref)
838
839 sumWeight_local(bin,k) = sumWeight_local(bin,k) + weight
840
841 meanCorrel_local(bin,k) = meanCorrel_local(bin,k) + &
842 correlation * weight
843 meanCorrelSquare_local(bin,k) = meanCorrelSquare_local(bin,k) + &
844 correlation**2 * weight
845 meanCovarianceSquare_local(bin,k) = meanCovarianceSquare_local(bin,k) + &
846 covariance**2 * weight
847 meanVarianceProduct_local(bin,k) = meanVarianceProduct_local(bin,k) + &
848 ensStdDev(iref,jref,k2)**2 * ensStdDev(iref,jref,k)**2 * weight
849 meanFourthMoment_local(bin,k) = meanFourthMoment_local(bin,k) + &
850 fourthMoment * weight
851 end do
852 end do
853 !$OMP END PARALLEL DO
854 end do ! var3D
855
856 end do ! iref
857 end do ! jref
858
859 deallocate(ensPert_local)
860
861 !- 2.2 Gather the all the info in processor 0
862 nSize = nkgdimEns * numbins
863 call rpn_comm_reduce(sumWeight_local ,sumWeight ,nSize, &
864 "mpi_double_precision","mpi_sum",0,"GRID",ier)
865 call rpn_comm_reduce(meanCorrel_local ,meanCorrel ,nSize, &
866 "mpi_double_precision","mpi_sum",0,"GRID",ier)
867 call rpn_comm_reduce(meanCorrelSquare_local ,meanCorrelSquare ,nSize, &
868 "mpi_double_precision","mpi_sum",0,"GRID",ier)
869 call rpn_comm_reduce(meanVarianceProduct_local ,meanVarianceProduct ,nSize, &
870 "mpi_double_precision","mpi_sum",0,"GRID",ier)
871 call rpn_comm_reduce(meanFourthMoment_local ,meanFourthMoment ,nSize, &
872 "mpi_double_precision","mpi_sum",0,"GRID",ier)
873 call rpn_comm_reduce(meanCovarianceSquare_local,meanCovarianceSquare,nSize, &
874 "mpi_double_precision","mpi_sum",0,"GRID",ier)
875
876 deallocate(sumWeight_local)
877 deallocate(meanCorrel_local)
878 deallocate(meanCorrelSquare_local)
879 deallocate(meanVarianceProduct_local)
880 deallocate(meanFourthMoment_local)
881 deallocate(meanCovarianceSquare_local)
882
883 if (mmpi_myid == 0) then
884 !- 2.3 Computation of the localization functions
885 allocate(localizationFunctions(numFunctions,numBins,nkgdimEns))
886
887 t1=dble((nens-1)**2)/dble(nens*(nens-3))
888 t2=dble(nens)/dble((nens-2)*(nens-3))
889 t3=dble(nens-1)/dble(nens*(nens-2)*(nens-3))
890
891 do jvar = 1, nvar3d
892 if (vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
893 nLevEns = nLevEns_M
894 else
895 nLevEns = nLevEns_T
896 endif
897 nLevStart = varLevOffset(jvar)+ 1
898 nLevEnd = varLevOffset(jvar)+ nLevEns
899 !$OMP PARALLEL DO PRIVATE (k,bin)
900 do k = nLevStart, nLevEnd
901 do bin = 1, nLevEns
902 meanCorrel(bin,k) = meanCorrel(bin,k) / sumWeight(bin,k)
903 meanCorrelSquare(bin,k) = meanCorrelSquare(bin,k) / sumWeight(bin,k)
904 meanCovarianceSquare(bin,k) = meanCovarianceSquare(bin,k) / sumWeight(bin,k)
905 meanVarianceProduct(bin,k) = meanVarianceProduct(bin,k) / sumWeight(bin,k)
906 meanFourthMoment(bin,k) = meanFourthMoment(bin,k) / sumWeight(bin,k)
907
908 if ( meanCovarianceSquare(bin,k) /= 0.d0 ) then
909 ! Form 1: General formulation (Eq. 19 in MMMB 2015 Part 2)
910 localizationFunctions(1,bin,k) = t1 - t2*meanFourthMoment(bin,k)/meanCovarianceSquare(bin,k) + &
911 t3*meanVarianceProduct(bin,k)/meanCovarianceSquare(bin,k)
912 ! Form 2: Gaussian sample distribution (Eq. 20 in MMMB 2015 Part 2)
913 localizationFunctions(2,bin,k) = dble(nens-1)/dble((nens+1)*(nens-2)) * &
914 (dble(nens-1)-meanVarianceProduct(bin,k)/meanCovarianceSquare(bin,k))
915 else
916 write(*,*) ' !!! Warning !!! meanCovarianceSquare = 0 in bin, level = ', bin, k
917 localizationFunctions(1,bin,k) = 0.d0
918 localizationFunctions(2,bin,k) = 0.d0
919 end if
920 ! Form 3: Gaussian sample distribution and correlation-based formulation (Eq. 21 in MMMB 2015 Part 2)
921 if ( meanCorrelSquare(bin,k) /= 0.d0 ) then
922 localizationFunctions(3,bin,k) = dble(nens-1)/dble((nens+1)*(nens-2)) * &
923 (dble(nens-1)-1.d0/meanCorrelSquare(bin,k))
924 else
925 write(*,*) ' !!! Warning !!! meanCorrelSquare = 0 in bin, level = ', bin, k
926 localizationFunctions(3,bin,k) = 0.d0
927 end if
928 end do
929 end do
930 !$OMP END PARALLEL DO
931 end do
932
933 !
934 !- 3. Estimation of localization radii (curve fitting)
935 !
936 allocate(localizationRadii(numFunctions,nkgdimEns))
937 allocate(distanceBinWeight(numBins))
938
939 call lfn_setup('FifthOrder') ! IN
940
941 localizationRadii(:,:) = 2.d0 ! First Guess (in ln(p) distance)
942 distanceBinWeight(:) = 1.d0 ! Even weight
943
944 do jvar = 1, nvar3d
945 if (vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
946 nLevEns = nLevEns_M
947 distanceBinInLnP => distanceBinInLnP_M
948 else
949 nLevEns = nLevEns_T
950 distanceBinInLnP => distanceBinInLnP_T
951 endif
952 nLevStart = varLevOffset(jvar)+ 1
953 nLevEnd = varLevOffset(jvar)+ nLevEns
954
955 write(*,*)
956 write(*,*) nomvar3d(jvar)
957
958 do f = 1, numFunctions
959
960 write(*,*)
961 write(*,*) 'Localization Function : ', f
962 do k = nLevStart, nLevEnd
963 kens = k-nLevStart+1
964 write(*,*) ' ----- EnsLev : ', k
965 call lfn_lengthscale( localizationRadii(f,k), & ! INOUT
966 rmse, & ! OUT
967 localizationFunctions(f,1:nLevEns,k), & ! IN
968 distanceBinInLnP(kens,:), & ! IN
969 distanceBinWeight(1:nLevEns), & ! IN
970 nLevEns ) ! IN
971 end do
972 end do
973 end do
974
975 !
976 !- 4. Write to file
977 !
978 if ( nWaveBand /= 1 ) then
979 if (.not. present(waveBandIndex_opt)) then
980 write(*,*) 'calcLocalizationRadii: No waveBandIndex was supplied!!!'
981 call utl_abort('calbmatrix_glb')
982 end if
983 write(wbnum,'(I2.2)') waveBandIndex_opt
984 end if
985
986 !- 4.1 Localization functions in txt format (for plotting purposes)
987 do jvar = 1, nvar3d
988 if ( nWaveBand == 1 ) then
989 outfilename = "./vertLocalizationFunctions_"//trim(nomvar3d(jvar))//".txt"
990 else
991 outfilename = "./vertLocalizationFunctions_"//trim(nomvar3d(jvar))//"_"//wbnum//".txt"
992 end if
993 open (unit=99,file=outfilename,action="write",status="new")
994
995 if(vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
996 nLevEns = nLevEns_M
997 PressureProfile => pressureProfile_M
998 distanceBinInLnP => distanceBinInLnP_M
999 else
1000 nLevEns = nLevEns_T
1001 PressureProfile => pressureProfile_T
1002 distanceBinInLnP => distanceBinInLnP_T
1003 endif
1004
1005 do k=1,nlevEns
1006 do bin = 1, nlevEns
1007 write(99,'(I3,2X,I3,2X,F7.2,2X,F7.3,2X,I7,2X,F6.4,2X,F6.4,2X,F6.4,2X,F6.4,2X,F6.4,2X,E10.3,2X,E10.3,2X,E10.3)') k, bin, &
1008 PressureProfile(bin)/100.d0, distanceBinInLnP(k,bin), nint(sumWeight(bin,varLevOffset(jvar)+k)), &
1009 meanCorrel(bin,varLevOffset(jvar)+k), &
1010 localizationFunctions(3,bin,varLevOffset(jvar)+k), &
1011 localizationFunctions(2,bin,varLevOffset(jvar)+k), &
1012 localizationFunctions(1,bin,varLevOffset(jvar)+k), &
1013 meanCorrelSquare(bin,varLevOffset(jvar)+k), &
1014 meanCovarianceSquare(bin,varLevOffset(jvar)+k), &
1015 meanVarianceProduct(bin,varLevOffset(jvar)+k), &
1016 meanFourthMoment(bin,varLevOffset(jvar)+k)
1017 end do
1018 end do
1019 close(unit=99)
1020 end do
1021
1022 !- 4.2 Localization radii in txt format (for plotting purposes)
1023 do jvar = 1, nvar3d
1024 if ( nWaveBand == 1 ) then
1025 outfilename = "./vertLocalizationRadii_"//trim(nomvar3d(jvar))//".txt"
1026 else
1027 outfilename = "./vertLocalizationRadii_"//trim(nomvar3d(jvar))//"_"//wbnum//".txt"
1028 end if
1029 open (unit=99,file=outfilename,action="write",status="new")
1030
1031 if(vnl_varLevelFromVarName(nomvar3d(jvar)).eq.'MM') then
1032 nLevEns = nLevEns_M
1033 PressureProfile => pressureProfile_M
1034 else
1035 nLevEns = nLevEns_T
1036 PressureProfile => pressureProfile_T
1037 endif
1038 do k=1,nlevEns
1039 write(99,'(I3,2X,F7.2,2X,F7.2,2X,F7.2,2X,F7.2)') k, PressureProfile(k)/100.d0, &
1040 localizationRadii(3,varLevOffset(jvar)+k), &
1041 localizationRadii(2,varLevOffset(jvar)+k), &
1042 localizationRadii(1,varLevOffset(jvar)+k)
1043 end do
1044 close(unit=99)
1045 end do
1046
1047 deallocate(localizationFunctions)
1048 deallocate(localizationRadii)
1049 deallocate(distanceBinWeight)
1050
1051 end if ! mmpi_myid == 0
1052
1053 deallocate(meanCorrelSquare)
1054 deallocate(meanCorrel)
1055 deallocate(meanCovarianceSquare)
1056 deallocate(meanVarianceProduct)
1057 deallocate(meanFourthMoment)
1058 deallocate(distanceBinInLnP_M)
1059 deallocate(distanceBinInLnP_T)
1060 deallocate(sumWeight)
1061 deallocate(gridPointWeight)
1062
1063 write(*,*) 'finished estimating the vertical localization radii...'
1064
1065 end subroutine calcVertLocalizationRadii
1066
1067end module menetrierDiag_mod