1module lamBmatrixHI_mod
2 ! MODULE lamBmatrixHI_mod (prefix='lbhi' category='2. B and R matrices')
3 !
4 !:Purpose: Performs transformation from control vector to analysis increment
5 ! using the homogeneous and isotropic background error covariance
6 ! matrix.
7 !
8 use midasMpi_mod
9 use horizontalCoord_mod
10 use verticalCoord_mod
11 use LamSpectralTransform_mod
12 use gridStateVector_mod
13 use lamAnalysisGridTransforms_mod
14 use utilities_mod
15 use gridVariableTransforms_mod
16 use varNameList_mod
17 use interpolation_mod
18 implicit none
19 save
20 private
21
22 ! public procedures
23 public :: lbhi_Setup, lbhi_bSqrt, lbhi_bSqrtAdj, lbhi_Finalize
24 public :: lbhi_expandToMPIglobal, lbhi_expandToMPIglobal_r4, lbhi_reduceToMPIlocal, lbhi_reduceToMPIlocal_r4
25
26 integer, parameter :: cv_model = 1
27 integer, parameter :: cv_bhi = 2
28 type :: lbhi_cv
29 character(len=4) :: NomVar(2)
30 character(len=2) :: GridType ! TT=Thermo, MM=Momentum, NS=Non-staggered
31 integer :: nlev
32 integer :: kDimStart
33 integer :: kDimEnd
34 real(8), allocatable :: GpStdDev(:,:,:)
35 integer, allocatable :: ip1(:)
36 end type lbhi_cv
37
38 integer,parameter :: nMaxControlVar = 10
39 type(lbhi_cv) :: ControlVariable(nMaxControlVar)
40
41 integer :: UWindID = -1
42 integer :: VWindID = -1
43
44 character(len=12) :: WindTransform
45
46 type(struct_hco), pointer :: hco_bhi ! Analysis horizontal grid parameters
47 type(struct_hco), pointer :: hco_bstats ! Grid-point std dev horizontal grid parameters
48
49 type(struct_lst) :: lst_bhi ! Spectral transform Parameters for B
50 type(struct_lst) :: lst_wind ! Spectral transform Parameters for Vort/Div -> Psi/Chi
51
52 real(8), allocatable :: bsqrt (:,:,:) ! B^1/2
53
54 integer :: nControlVariable
55 integer :: trunc
56 integer :: nksdim
57 integer :: nkgdim
58 integer :: cvDim
59 integer :: cvDim_mpiglobal
60
61 integer :: nlev_M
62 integer :: nlev_T
63
64 logical :: regrid
65 logical :: initialized = .false.
66
67 integer :: LatPerPE, LatPerPEmax, myLatBeg, myLatEnd
68 integer :: LonPerPE, LonPerPEmax, myLonBeg, myLonEnd
69
70 real(8) :: scaleFactor(vco_maxNumLevels)
71
72 character(len=8), parameter :: BStatsFilename = './bgcov'
73
74contains
75
76 !--------------------------------------------------------------------------
77 ! lbhi_SETUP
78 !--------------------------------------------------------------------------
79 subroutine lbhi_Setup( hco_anl_in, hco_core_in, vco_anl_in, cvDim_out )
80 implicit none
81
82 ! Arguments:
83 type(struct_hco), pointer, intent(in) :: hco_anl_in
84 type(struct_hco), pointer, intent(in) :: hco_core_in
85 type(struct_vco), pointer, intent(in) :: vco_anl_in
86 integer, intent(out) :: cvDim_out
87
88 ! Locals:
89 integer :: var
90 integer :: iu_bstats = 0
91 integer :: iu_flnml = 0
92 integer :: ier, fnom, fstouv, fstfrm, fclos, levIndex, nLev
93 logical :: FileExist
94 type(struct_vco), pointer :: vco_file => null()
95 integer :: ntrunc
96
97 NAMELIST /NAMBHI/ntrunc,scaleFactor
98
99 write(*,*)
100 write(*,*) 'lbhi_Setup: Starting...'
101
102 !
103 !- 0. Read namelist options
104 !
105 ntrunc = 75 ! default values
106 scaleFactor(:) = 0.0d0 ! default values
107
108 ier = fnom(iu_flnml,'./flnml','FTN+SEQ+R/O',0)
109 write(*,*)
110 write(*,*) 'lbhi_setup: Reading namelist, ier = ',ier
111 read(iu_flnml,nml=nambhi)
112 write(*,nml=nambhi)
113 ier = fclos(iu_flnml)
114
115 nLev = max(max(vco_anl_in%nlev_M,vco_anl_in%nlev_T),1)
116
117 do levIndex = 1, nLev
118 if ( scaleFactor(levIndex) > 0.0d0 ) then
119 scaleFactor(levIndex) = sqrt(scaleFactor(levIndex))
120 else
121 scaleFactor(levIndex) = 0.0d0
122 end if
123 end do
124
125 write(*,*) ' sum(scaleFactor) : ',sum(scaleFactor(1:nLev))
126 if ( sum(scaleFactor(1:nLev)) == 0.0d0 ) then
127 write(*,*) 'lambmatrixHI: scaleFactor=0, skipping rest of setup'
128 cvDim_out = 0
129 return
130 end if
131
132 !- Setup the LAM analysis grid metrics
133 call lgt_SetupFromHCO( hco_anl_in, hco_core_in ) ! IN
134
135 trunc = ntrunc
136 write(*,*)
137 write(*,*) 'Spectral TRUNCATION = ', trunc
138
139 !
140 !- 1. Open the background stats file
141 !
142 inquire(file=trim(BStatsFilename), exist=FileExist)
143
144 if ( FileExist ) then
145 ier = fnom(iu_bstats,trim(BStatsFilename),'RND+OLD+R/O',0)
146 if ( ier == 0 ) then
147 write(*,*)
148 write(*,*) 'Background Stats File :', trim(BStatsFilename)
149 write(*,*) 'opened as unit file ',iu_bstats
150 ier = fstouv(iu_bstats,'RND+OLD')
151 else
152 write(*,*)
153 write(*,*) 'lbhi_Setup: Error in opening the background stats file'
154 write(*,*) trim(BStatsFilename)
155 call utl_abort('lbhi_Setup')
156 end if
157 else
158 write(*,*)
159 write(*,*) 'lbhi_Setup: The background stats file DOES NOT EXIST'
160 write(*,*) trim(BStatsFilename)
161 call utl_abort('lbhi_Setup')
162 end if
163
164 ! Check if analysisgrid and covariance file have the same vertical levels
165 call vco_SetupFromFile( vco_file, & ! OUT
166 BStatsFilename ) ! IN
167 if (.not. vco_equal(vco_anl_in,vco_file)) then
168 call utl_abort('lamBmatrixHI: vco from analysisgrid and cov file do not match')
169 end if
170
171 !
172 !- 2. Set some variables
173 !
174 hco_bhi => hco_anl_in
175 nlev_M = vco_anl_in%nlev_M
176 nlev_T = vco_anl_in%nlev_T
177
178 !- Read variables and vertical grid info from the background stats file
179 call lbhi_GetControlVariableInfo( iu_bstats ) ! IN
180 call lbhi_GetHorizGridInfo()
181
182 nkgdim = 0
183 do var = 1, nControlVariable
184 allocate( ControlVariable(var)%GpStdDev (1:hco_bhi%ni, 1:hco_bhi%nj, 1:ControlVariable(var)%nlev) )
185 allocate( ControlVariable(var)%ip1 (1:ControlVariable(var)%nlev) )
186
187 if (ControlVariable(var)%GridType == 'TH') then
188 ControlVariable(var)%ip1(:) = vco_anl_in%ip1_T(:)
189 elseif (ControlVariable(var)%GridType == 'MM') then
190 ControlVariable(var)%ip1(:) = vco_anl_in%ip1_M(:)
191 else
192 ControlVariable(var)%ip1(:) = 0
193 end if
194
195 ControlVariable(var)%kDimStart = nkgdim + 1
196 nkgdim = nkgdim + ControlVariable(var)%nlev
197 ControlVariable(var)%kDimEnd = nkgdim
198 end do
199
200 nksdim = nkgdim ! + nlev
201
202 allocate( bsqrt (1:nksdim, 1:nksdim ,0:trunc) )
203
204 !- 2.2 Initialized the LAM spectral transform
205 call mmpi_setup_lonbands(hco_bhi%ni, & ! IN
206 lonPerPE, lonPerPEmax, myLonBeg, myLonEnd ) ! OUT
207
208 call mmpi_setup_latbands(hco_bhi%nj, & ! IN
209 latPerPE, latPerPEmax, myLatBeg, myLatEnd ) ! OUT
210
211 call lst_Setup(lst_bhi, & ! OUT
212 hco_bhi%ni, hco_bhi%nj, & ! IN
213 hco_bhi%dlon, trunc, & ! IN
214 'LatLonMN', maxlevels_opt=nksdim) ! IN
215
216 cvDim = nkgdim * lst_bhi%nla * lst_bhi%nphase
217 cvDim_out = cvDim
218
219 ! also compute mpiglobal control vector dimension
220 call rpn_comm_allreduce(cvDim,cvDim_mpiglobal,1,"mpi_integer","mpi_sum","GRID",ier)
221
222 !- 2.3 Initialized the Wind spectral transform
223 if ( trim(WindTransform) == 'VortDiv' ) then
224 call lst_Setup(lst_wind, & ! OUT
225 hco_bhi%ni, hco_bhi%nj, & ! IN
226 hco_bhi%dlon, trunc, & ! IN
227 'LatLonMN', maxlevels_opt=nlev_M) ! IN
228 end if
229
230 !
231 !- 3. Read info from the background error statistics file
232 !
233 call lbhi_ReadStats( iu_bstats ) ! IN
234
235 !
236 !- 4. Close the background stats files
237 !
238 ier = fstfrm(iu_bstats)
239 ier = fclos (iu_bstats)
240
241 !
242 !- 6. Ending
243 !
244 initialized = .true.
245
246 write(*,*)
247 write(*,*) 'lbhi_Setup: Done!'
248
249 end subroutine lbhi_Setup
250
251 !--------------------------------------------------------------------------
252 ! lbhi_GetControlVariableInfo
253 !--------------------------------------------------------------------------
254 subroutine lbhi_GetControlVariableInfo( iu_bstats )
255 implicit none
256
257 ! Arguments:
258 integer, intent(in) :: iu_bstats
259
260 ! Locals:
261 integer :: key, fstinf, fstlir, fstlir_s
262 integer :: ni, nj, nlev
263 integer :: dateo, nk
264 integer :: ip1, ip2, ip3
265 integer :: var
266 character(len=4 ) :: nomvar
267 character(len=2 ) :: typvar
268 character(len=12) :: etiket
269 character(len=4), allocatable :: ControlModelVarnameList(:)
270 character(len=4), allocatable :: ControlBhiVarnameList (:)
271 character(len=2), allocatable :: ControlVarGridTypeList (:)
272 integer, allocatable :: ControlVarNlevList (:)
273
274 !
275 !- 1. How Many Control Variables do we have?
276 !
277 dateo = -1
278 etiket = 'NLEV'
279 ip1 = -1
280 ip2 = -1
281 ip3 = -1
282 typvar = ' '
283 nomvar = 'CVL'
284
285 key = fstinf( iu_bstats, & ! IN
286 ni, nj, nk, & ! OUT
287 dateo, etiket, ip1, ip2, ip3, typvar, nomvar )! IN
288
289 if (key < 0) then
290 write(*,*)
291 write(*,*) 'lbhi_GetControlVariableInfo: Unable to find variable =',nomvar
292 call utl_abort('lbhi_GetControlVariableInfo')
293 end if
294
295 nControlVariable = ni
296 write(*,*)
297 write(*,*) 'Number of Control Variables found = ', nControlVariable
298
299 allocate(ControlModelVarnameList(nControlVariable))
300 allocate(ControlBhiVarnameList (nControlVariable))
301 allocate(ControlVarGridTypeList (nControlVariable))
302 allocate(ControlVarNlevList (nControlVariable))
303
304 !
305 !- 2. Read the info from the input file
306 !
307 nomvar = 'CVN'
308
309 etiket = 'MODEL'
310 key = fstlir_s(ControlModelVarnameList, & ! OUT
311 iu_bstats, & ! IN
312 ni, nj, nlev, & ! OUT
313 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
314 if (key < 0) then
315 write(*,*)
316 write(*,*) 'lbhi_GetControlVariableInfo: Cannot find variable ', nomvar
317 call utl_abort('lbhi_GetControlVariableInfo')
318 end if
319
320 etiket = 'B_HI'
321 key = fstlir_s(ControlBhiVarnameList, & ! OUT
322 iu_bstats, & ! IN
323 ni, nj, nlev, & ! OUT
324 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
325 if (key < 0) then
326 write(*,*)
327 write(*,*) 'lbhi_GetControlVariableInfo: Cannot find variable ', nomvar
328 call utl_abort('lbhi_GetControlVariableInfo')
329 end if
330
331
332 nomvar = 'CVL'
333
334 etiket = 'NLEV'
335 key = fstlir (ControlVarNlevList, & ! OUT
336 iu_bstats, & ! IN
337 ni, nj, nlev, & ! OUT
338 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
339 if (key < 0) then
340 write(*,*)
341 write(*,*) 'lbhi_GetControlVariableInfo: Cannot find variable ', nomvar
342 call utl_abort('lbhi_GetControlVariableInfo')
343 end if
344
345 etiket = 'LEVTYPE'
346 key = fstlir_s(ControlVarGridTypeList, & ! OUT
347 iu_bstats, & ! IN
348 ni, nj, nlev, & ! OUT
349 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
350 if (key < 0) then
351 write(*,*)
352 write(*,*) 'lbhi_GetControlVariableInfo: Cannot find variable ', nomvar
353 call utl_abort('lbhi_GetControlVariableInfo')
354 end if
355
356 !
357 !- 3. Introduce the info in the ControlVariable structure
358 !
359 do var = 1, nControlVariable
360 ControlVariable(var)%nomvar(cv_model)= trim(ControlModelVarnameList(var))
361 ControlVariable(var)%nomvar(cv_bhi) = trim(ControlBhiVarnameList(var))
362 ControlVariable(var)%nlev = ControlVarNlevList(var)
363 ControlVariable(var)%GridType = trim(ControlVarGridTypeList(var))
364
365 if (trim(ControlVariable(var)%nomvar(cv_model)) == 'UU' ) then
366 UWindID = var
367 else if (trim(ControlVariable(var)%nomvar(cv_model)) == 'VV' ) then
368 VWindID = var
369 end if
370
371 if ( trim(ControlVariable(var)%nomvar(cv_model)) == 'LQ' ) then
372 ControlVariable(var)%nomvar(cv_model) = 'HU' ! PATCH because gridStateVector uses HU
373 end if
374
375 write(*,*)
376 write(*,*) 'nomvar(cv_model) = ', ControlVariable(var)%nomvar(cv_model)
377 write(*,*) 'nomvar(cv_bhi) = ', ControlVariable(var)%nomvar(cv_bhi)
378 write(*,*) 'nlev = ', ControlVariable(var)%nlev
379 write(*,*) 'gridtype = ', ControlVariable(var)%GridType
380 end do
381
382 deallocate(ControlModelVarnameList)
383 deallocate(ControlBhiVarnameList)
384 deallocate(ControlVarGridTypeList)
385 deallocate(ControlVarNlevList)
386
387 !
388 !- 4. Error traps
389 !
390
391 !- Make sure that all the control variables are present in GridStateVector
392 do var = 1, nControlVariable
393 if ( .not. gsv_varExist(varName=ControlVariable(var)%nomvar(cv_model)) ) then
394 write(*,*)
395 write(*,*) 'lbhi_GetControlVariableInfo: The following variable is MISSING in GridStateVector'
396 write(*,*) trim(ControlVariable(var)%nomvar(cv_model))
397 call utl_abort('lbhi_GetControlVariableInfo')
398 end if
399 end do
400
401 !
402 !- 5. Set the type of momentum control variables
403 !
404 if (UWindID /= -1 .and. VWindID /= -1) then
405 if ( trim(ControlVariable(UWindID)%nomvar(cv_model)) == 'UU' .and. &
406 trim(ControlVariable(UWindID)%nomvar(cv_bhi)) == 'PP' .and. &
407 trim(ControlVariable(VWindID)%nomvar(cv_model)) == 'VV' .and. &
408 trim(ControlVariable(VWindID)%nomvar(cv_bhi)) == 'CC' ) then
409 write(*,*)
410 write(*,*) 'Momentum Control Variables = Psi-Chi'
411 WindTransform = 'PsiChi'
412 else if ( trim(ControlVariable(UWindID)%nomvar(cv_model)) == 'UU' .and. &
413 trim(ControlVariable(UWindID)%nomvar(cv_bhi)) == 'QR' .and. &
414 trim(ControlVariable(VWindID)%nomvar(cv_model)) == 'VV' .and. &
415 trim(ControlVariable(VWindID)%nomvar(cv_bhi)) == 'DD' ) then
416 write(*,*)
417 write(*,*) 'Momentum Control Variables = Vort-Div'
418 WindTransform = 'VortDiv'
419 else if ( trim(ControlVariable(UWindID)%nomvar(cv_model)) == 'UU' .and. &
420 trim(ControlVariable(UWindID)%nomvar(cv_bhi)) == 'UU' .and. &
421 trim(ControlVariable(VWindID)%nomvar(cv_model)) == 'VV' .and. &
422 trim(ControlVariable(VWindID)%nomvar(cv_bhi)) == 'VV' ) then
423 write(*,*)
424 write(*,*) 'Momentum Control Variables = U-V '
425 WindTransform = 'UV'
426 else
427 call utl_abort('lbhi_GetControlVariableInfo: Unkown Wind Tranform')
428 end if
429 end if
430
431 end subroutine lbhi_GetControlVariableInfo
432
433 !--------------------------------------------------------------------------
434 ! lbhi_GetHorizGridInfo
435 !--------------------------------------------------------------------------
436 subroutine lbhi_GetHorizGridInfo()
437 implicit none
438
439 ! Locals:
440 character(len=4) :: varName
441
442 !
443 !- 1. Get horizontal grid parameters
444 !
445 varName = ControlVariable(1)%nomvar(cv_bhi)
446
447 call hco_setupFromFile(hco_bstats, BStatsFilename, ' ', 'bstats', & ! IN
448 varName_opt=varName) ! IN
449
450 !- 1.3 Regridding needed ?
451 if ( hco_equal(hco_bstats,hco_bhi) ) then
452 Regrid = .false.
453 write(*,*)
454 write(*,*) 'lbhi_GetHorizGridInfo: No Horizontal regridding needed'
455 else
456 Regrid = .true.
457 write(*,*)
458 write(*,*) 'lbhi_GetHorizGridInfo: Horizontal regridding is needed'
459 end if
460
461 end subroutine lbhi_GetHorizGridInfo
462
463 !--------------------------------------------------------------------------
464 ! lbhi_READSTATS
465 !--------------------------------------------------------------------------
466 subroutine lbhi_ReadStats( iu_bstats )
467 implicit none
468
469 ! Arguments:
470 integer, intent(in) :: iu_bstats
471
472 !
473 !- 1. Read the background error statistics
474 !
475
476 !- 1.1 Verical correlations of control variables in spectral space
477 call lbhi_ReadBSqrt( iu_bstats ) ! IN
478
479 !- 1.2 Mass - Rotational wind statistical linear balance operator
480
481 ! JFC: Pas encore code
482 !if ( usePtoT ) then
483 ! call lbhi_ReadPtoT( iu_bstats, PtoT_Type )
484 !end if
485
486 !- 1.3 Read grid-point standard deviations of control variables
487 call lbhi_ReadGridPointStdDev(iu_bstats ) ! IN
488
489 end subroutine lbhi_ReadStats
490
491 !--------------------------------------------------------------------------
492 ! lbhi_ReadBSqrt
493 !--------------------------------------------------------------------------
494 subroutine lbhi_ReadBSqrt( iu_bstats )
495 implicit none
496
497 ! Arguments:
498 integer, intent(in) :: iu_bstats
499
500 ! Locals:
501 real(8), allocatable :: bsqrt2d (:,:)
502 integer :: key, fstinf, fstinl, totwvnb, infon
503 integer, parameter :: nmax=2000
504 integer :: liste(nmax)
505 integer :: ip1, ip2, ip3
506 integer :: ni_t, nj_t, nlev_t, dateo
507 character(len=4 ) :: nomvar
508 character(len=2 ) :: typvar
509 character(len=12) :: etiket
510
511 dateo = -1
512 etiket = 'B_SQUAREROOT'
513 ip1 = -1
514 ip3 = -1
515 typvar = ' '
516 nomvar = 'ZN'
517
518 !
519 !- 1. Find the truncation in the stats file
520 !
521 ip2 = -1
522
523 key = fstinl(iu_bstats, & ! IN
524 ni_t, nj_t, nlev_t, & ! OUT
525 dateo, etiket, ip1, ip2, ip3, typvar, nomvar, & ! IN
526 liste, infon, & ! OUT
527 nmax ) ! IN
528
529 if (key >= 0) then
530 !- 1.2 Ensure spectral trunctation are the same
531 if ( infon - 1 /= trunc ) then
532 write(*,*)
533 write(*,*) 'lbhi_ReadBSqrt: Truncation here and on stats file different'
534 write(*,*) 'VAR truncation = ', trunc
535 write(*,*) 'Stats file truncation = ', infon-1
536 call utl_abort('lbhi_ReadBSqrt')
537 end if
538 else
539 write(*,*)
540 write(*,*) 'lbhi_ReadBSqrt: Cannot find B square-root ', nomvar
541 call utl_abort('lbhi_ReadBSqrt')
542 end if
543
544 !
545 !- 2. Read B^0.5
546 !
547 allocate( bsqrt2d (1:nksdim, 1:nksdim) )
548
549 do totwvnb = 0, trunc
550
551 ip2 = totwvnb
552
553 !- 2.1 Check if field exists and its dimensions
554 key = fstinf( iu_bstats, & ! IN
555 ni_t, nj_t, nlev_t, & ! OUT
556 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
557
558 if (key >= 0) then
559 !- 2.2 Ensure that the number of vertical levels are compatible
560 if ( ni_t /= nksdim .or. nj_t /= nksdim ) then
561 write(*,*)
562 write(*,*) 'lbhi_ReadBSqrt: BG stat levels inconsitencies'
563 write(*,*) 'for BSQRT: ni_t, nj_t, nksdim =', ni_t, nj_t, nksdim
564 call utl_abort('lbhi_ReadBSqrt')
565 endif
566
567 !- 2.3 Reading
568 key = utl_fstlir( bsqrt2d, & ! OUT
569 iu_bstats, & ! IN
570 ni_t, nj_t, nlev_t, & ! OUT
571 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
572 else
573 write(*,*)
574 write(*,*) 'lbhi_ReadBSqrt: Cannot find BSQRT for totwvnb = ', totwvnb
575 call utl_abort('lbhi_ReadBSqrt')
576 end if
577
578 !- 2.4 Transfer to a 3D array
579 bsqrt(:,:,totwvnb) = bsqrt2d(:,:)
580
581 end do
582
583 deallocate( bsqrt2d )
584
585 end subroutine lbhi_ReadBSqrt
586
587 !--------------------------------------------------------------------------
588 ! lbhi_ReadGridPointStdDev
589 !--------------------------------------------------------------------------
590 subroutine lbhi_ReadGridPointStdDev(iu_bstats)
591 implicit none
592
593 ! Locals:
594 integer, intent(in) :: iu_bstats
595
596 ! Locals:
597 real(8), allocatable :: StdDev2D(:,:)
598 real(8), allocatable :: StdDev2D_Regrid(:,:)
599 integer :: ezdefset, ier
600 integer :: ni_t, nj_t, nlev_t, var, k
601 integer :: dateo, ip1,ip2,ip3
602 character(len=4 ) :: nomvar
603 character(len=2 ) :: typvar
604 character(len=12) :: etiket
605 real(8) :: UnitConv
606
607 !
608 !- 1. Read grid point standard deviations
609 !
610 allocate( StdDev2D(1:hco_bstats%ni,1:hco_bstats%nj) )
611 if (Regrid) then
612 allocate( StdDev2D_Regrid(1:hco_bhi%ni, 1:hco_bhi%nj) )
613 ier = ezdefset(hco_bhi%EZscintID, hco_bstats%EZscintID) ! IN
614 end if
615
616 !- 1.1 Loop over Control Variables
617 do var = 1, nControlVariable
618
619 !- 1.2 Loop over vertical Levels
620 do k = 1, ControlVariable(var)%nlev
621 dateo = -1
622 ip1 = ControlVariable(var)%ip1(k)
623 ip2 = -1
624 ip3 = -1
625 typvar = ' '
626 nomvar = trim(ControlVariable(var)%nomvar(cv_bhi))
627 etiket = 'STDDEV'
628 if ( trim(nomvar) == 'P0') then
629 UnitConv = 100.0d0 ! hPa -> Pa
630 else
631 UnitConv = 1.0d0
632 end if
633
634 !- 1.2.1 Reading
635 ier = utl_fstlir( StdDev2D, & ! OUT
636 iu_bstats, & ! IN
637 ni_t, nj_t, nlev_t, & ! OUT
638 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
639
640 if (ier < 0) then
641 write(*,*)
642 write(*,*) 'lbhi_ReadGridPointStdDev: Cannot find Std Deviations'
643 write(*,*) 'nomvar =', trim(ControlVariable(var)%nomvar(cv_bhi))
644 write(*,*) 'etiket =', trim(etiket)
645 write(*,*) 'ip1 =', ControlVariable(var)%ip1(k)
646 call utl_abort('lbhi_ReadGridPointStdDev')
647 end if
648
649 if (ni_t /= hco_bstats%ni .or. nj_t /= hco_bstats%nj) then
650 write(*,*)
651 write(*,*) 'lbhi_ReadGridPointStdDev: Invalid dimensions for ...'
652 write(*,*) 'nomvar =', trim(ControlVariable(var)%nomvar(cv_bhi))
653 write(*,*) 'etiket =', trim(etiket)
654 write(*,*) 'ip1 =', ControlVariable(var)%ip1(k)
655 write(*,*) 'Found ni,nj =', ni_t, nj_t
656 write(*,*) 'Should be =', hco_bstats%ni, hco_bstats%nj
657 call utl_abort('lbhi_ReadGridPointStdDev')
658 end if
659
660 !- 1.2.2 Regrid (if necessary) and transfer to 3D array
661 if ( .not. Regrid) then
662 ControlVariable(var)%GpStdDev(:,:,k) = StdDev2D(:,:)
663 else
664 ! Note: EZSCINT setup was done above
665 ier = int_hInterpScalar(StdDev2D_Regrid, StdDev2D, interpDegree='LINEAR')
666 ControlVariable(var)%GpStdDev(:,:,k) = StdDev2D_Regrid(:,:)
667 end if
668
669 !- 1.3 Scaling
670 ControlVariable(var)%GpStdDev(:,:,k) = ControlVariable(var)%GpStdDev(:,:,k) * &
671 UnitConv * scaleFactor(k)
672
673 end do
674
675 end do
676
677 deallocate( StdDev2D )
678 if (Regrid) then
679 deallocate( StdDev2D_Regrid )
680 end if
681
682 end subroutine lbhi_ReadGridPointStdDev
683
684 !--------------------------------------------------------------------------
685 ! lbhi_bSqrt
686 !--------------------------------------------------------------------------
687 subroutine lbhi_bSqrt(controlVector_in, statevector, stateVectorRef_opt)
688 implicit none
689
690 ! Arguments:
691 real(8), intent(in) :: controlVector_in(cvDim)
692 type(struct_gsv), intent(inout) :: statevector
693 type(struct_gsv), optional, intent(in) :: statevectorRef_opt
694
695 ! Locals:
696 real(8), allocatable :: gd_out(:,:,:)
697 real(8), allocatable :: hiControlVector(:,:,:)
698
699 if ( .not. initialized ) then
700 if(mmpi_myid == 0) write(*,*) 'lbhi_bSqrt: LAM_bMatrixHI not initialized'
701 return
702 endif
703
704 write(*,*)
705 write(*,*) 'lbhi_bSqrt: Starting ...'
706
707 !
708 !- 1. Extract data from the 1D controlVector array
709 !
710 allocate( hiControlVector(lst_bhi%nla, lst_bhi%nphase, nksdim) )
711
712 call lbhi_cain( controlVector_in, & ! IN
713 hiControlVector ) ! OUT
714
715 !
716 !- 2. Move from control variables space to model variables space
717 !
718 allocate( gd_out (myLonBeg:myLonEnd, myLatBeg:myLatEnd, nksdim) )
719
720 call lbhi_cv2gd( hiControlVector, & ! IN
721 gd_out ) ! OUT
722
723 deallocate(hiControlVector)
724
725 !
726 !- 3. Transfer results to statevector structure
727 !
728 call StatevectorInterface( statevector, & ! INOUT
729 gd_out, & ! IN
730 'ToStateVector' ) ! IN
731 deallocate(gd_out)
732
733 !
734 !- 4. Convert LQ_inc to HU_inc
735 !
736 if ( gsv_varExist(varName='HU') ) then
737 call gvt_transform( statevector, & ! INOUT
738 'LQtoHU_tlm', & ! IN
739 stateVectorRef_opt=stateVectorRef_opt ) ! IN
740 end if
741
742 write(*,*)
743 write(*,*) 'lbhi_bSqrt: Done'
744
745 end subroutine lbhi_bSqrt
746
747 !--------------------------------------------------------------------------
748 ! lbhi_bSqrtAdj
749 !--------------------------------------------------------------------------
750 subroutine lbhi_bSqrtAdj(statevector, controlVector_out, stateVectorRef_opt)
751 implicit none
752
753 ! Arguments:
754 real(8), intent(out) :: controlVector_out(cvDim)
755 type(struct_gsv), intent(inout) :: statevector
756 type(struct_gsv), optional, intent(in) :: statevectorRef_opt
757
758 ! Locals:
759 real(8), allocatable :: gd_in(:,:,:)
760 real(8), allocatable :: hiControlVector(:,:,:)
761
762 if ( .not. initialized ) then
763 if(mmpi_myid == 0) write(*,*) 'lbhi_bSqrtAdj: LAM_bMatrixHI not initialized'
764 return
765 endif
766
767 write(*,*)
768 write(*,*) 'lbhi_bSqrtAdj: Starting ...'
769
770 !
771 !- 4. Convert LQ_inc to HU_inc
772 !
773 if ( gsv_varExist(varName='HU') ) then
774 call gvt_transform( statevector, & ! INOUT
775 'LQtoHU_ad', & ! IN
776 stateVectorRef_opt=stateVectorRef_opt ) ! IN
777 end if
778
779 !
780 !- 3. Extract data from the StateVector
781 !
782 allocate( gd_in(myLonBeg:myLonEnd, myLatBeg:myLatEnd, nksdim) )
783
784 call StatevectorInterface ( statevector, & ! IN
785 gd_in, & ! OUT
786 'FromStateVector' ) ! IN
787
788 !
789 !- 2. Move from model variables space to control variables space
790 !
791 allocate( hiControlVector(lst_bhi%nla, lst_bhi%nphase, nksdim) )
792 hiControlVector(:,:,:) = 0.d0
793
794 call lbhi_cv2gdAdj( hiControlVector, & ! OUT
795 gd_in ) ! IN
796
797 !
798 !- 1. Put data into the 1D controlVector array
799 !
800 controlVector_out(:) = 0.d0
801 call lbhi_cainAdj(controlVector_out, hiControlVector)
802
803 deallocate(gd_in)
804 deallocate(hiControlVector)
805
806 write(*,*)
807 write(*,*) 'lbhi_bSqrtAdj: Done'
808
809 end subroutine lbhi_bSqrtAdj
810
811 !--------------------------------------------------------------------------
812 ! lbhi_cv2gd
813 !--------------------------------------------------------------------------
814 subroutine lbhi_cv2gd(hiControlVector_in, gd_out)
815 implicit none
816
817 ! Arguments:
818 real(8), intent(inout) :: hiControlVector_in(lst_bhi%nla, lst_bhi%nphase, nksdim)
819 real(8), intent(out) :: gd_out(myLonBeg:myLonEnd ,myLatBeg:myLatEnd ,1:nksdim)
820
821 ! Locals:
822 real(8), allocatable :: uphy(:,:,:)
823 real(8), allocatable :: vphy(:,:,:)
824 real(8), allocatable :: psi(:,:,:)
825 real(8), allocatable :: chi(:,:,:)
826 integer :: kstart, kend, var
827 character(len=19) :: kind
828
829 !
830 !- 1. B^1/2 * xi (in spectral space)
831 !
832 call lbhi_bSqrtXi(hiControlVector_in) ! INOUT
833
834 !
835 !- 2. Spectral Space -> Grid Point Space
836 !
837 kind = 'SpectralToGridPoint'
838 call lst_VarTransform(lst_bhi, & ! IN
839 hiControlVector_in, & ! IN
840 gd_out, & ! OUT
841 kind, nksdim ) ! IN
842
843 !
844 !- 3. Multiply by the grid point standard deviations
845 !
846 !$OMP PARALLEL DO PRIVATE(var,kstart,kend)
847 do var = 1, nControlVariable
848 kstart = ControlVariable(var)%kDimStart
849 kend = ControlVariable(var)%kDimEnd
850 gd_out(:,:,kstart:kend) = gd_out(:,:,kstart:kend) * ControlVariable(var)%GpStdDev(myLonBeg:myLonEnd,myLatBeg:myLatEnd,:)
851 end do
852 !$OMP END PARALLEL DO
853
854 !
855 !- 4. Momentum variables transform
856 !
857 if ( UWindID /= -1 .and. VWindID /= -1) then
858 if ( ControlVariable(UWindID)%nlev /= nlev_M .or. &
859 ControlVariable(VWindID)%nlev /= nlev_M ) then
860 call utl_abort('lbhi_cv2gd: Error in Wind related parameters')
861 end if
862
863 if ( trim(WindTransform) /= 'UV') then
864
865 allocate(uphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
866 allocate(vphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
867 allocate(psi (myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
868 allocate(chi (myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
869
870 !- 4.1 Vort / Div -> Psi / Chi
871 if ( trim(WindTransform) == 'VortDiv') then
872
873 ! 4.1.1 Putting vorticity in psi array and divergence in chi array
874 psi(:,:,:) = gd_out(:,:,ControlVariable(UWindID)%kDimStart:ControlVariable(UWindID)%kDimEnd)
875 chi(:,:,:) = gd_out(:,:,ControlVariable(VWindID)%kDimStart:ControlVariable(VWindID)%kDimEnd)
876
877 ! 4.1.2 Vort -> Psi
878 call lst_Laplacian(lst_wind, & ! IN
879 Psi, & ! INOUT
880 'Inverse', nlev_M) ! IN
881
882 ! 4.1.3 Div -> Chi
883 call lst_Laplacian(lst_wind, & ! IN
884 Chi, & ! INOUT
885 'Inverse', nlev_M) ! IN
886
887 end if
888
889 !- 4.2 Psi / Chi -> U-wind / V-wind
890 if ( trim(WindTransform) == 'PsiChi') then
891 psi(:,:,:) = gd_out(:,:,ControlVariable(UWindID)%kDimStart:ControlVariable(UWindID)%kDimEnd)
892 chi(:,:,:) = gd_out(:,:,ControlVariable(VWindID)%kDimStart:ControlVariable(VWindID)%kDimEnd)
893 end if
894
895 ! 4.2.1 Do Transform
896 call lgt_PsiChiToUV(psi, chi, & ! IN
897 uphy, vphy, & ! OUT
898 nlev_M) ! IN
899
900 ! 4.2.2 Insert results in gd_out and deallocate memories
901 gd_out(:,:,1 : nlev_M) = uphy(:,:,:)
902 gd_out(:,:,nlev_M+1:2*nlev_M) = vphy(:,:,:)
903
904 deallocate(chi)
905 deallocate(psi)
906 deallocate(vphy)
907 deallocate(uphy)
908
909 end if
910
911 end if
912
913 end subroutine lbhi_cv2gd
914
915 !--------------------------------------------------------------------------
916 ! lbhi_cv2gdAdj
917 !--------------------------------------------------------------------------
918 subroutine lbhi_cv2gdAdj(hiControlVector_out, gd_in)
919 implicit none
920
921 ! Arguments:
922 real(8), intent(out) :: hiControlVector_out(lst_bhi%nla, lst_bhi%nphase, nksdim)
923 real(8), intent(inout) :: gd_in(myLonBeg:myLonEnd, myLatBeg:myLatEnd ,1:nksdim)
924
925 ! Locals:
926 real(8), allocatable :: uphy(:,:,:)
927 real(8), allocatable :: vphy(:,:,:)
928 real(8), allocatable :: psi(:,:,:)
929 real(8), allocatable :: chi(:,:,:)
930 integer :: kstart, kend, var
931 character(len=19) :: kind
932
933 !
934 !- 4. Momentum variables transform
935 !
936 if ( UWindID /= -1 .and. VWindID /= -1) then
937 if ( ControlVariable(UWindID)%nlev /= nlev_M .or. &
938 ControlVariable(VWindID)%nlev /= nlev_M ) then
939 call utl_abort('lbhi_cv2gdadj: Error in Wind related parameters')
940 end if
941
942 if ( trim(WindTransform) /= 'UV' ) then
943
944 allocate(uphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
945 allocate(vphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
946 allocate(psi (myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
947 allocate(chi (myLonBeg:myLonEnd,myLatBeg:myLatEnd,1:nlev_M))
948
949 !- 4.2 U-wind / V-wind -> Psi / Chi
950
951 ! 4.2.2 Extract winds
952 uphy(:,:,:) = gd_in(:,:,1 : nlev_M)
953 vphy(:,:,:) = gd_in(:,:,nlev_M+1:2*nlev_M)
954
955 ! 4.2.1 Do Transform
956 call lgt_PsiChiToUVAdj( psi, chi, & ! OUT
957 uphy, vphy, & ! IN
958 nlev_M) ! IN
959
960 !- 4.1 Psi / Chi -> Vort / Div (Laplacian and inverse Laplacian are auto-adjoint operators)
961 if ( trim(WindTransform) == 'VortDiv' ) then
962
963 ! 4.1.2 Psi -> Vort
964 call lst_Laplacian(lst_wind, & ! IN
965 Psi, & ! INOUT
966 'Inverse', nlev_M) ! IN
967
968 ! 4.1.3 Chi -> Vort
969 call lst_Laplacian(lst_wind, & ! IN
970 Chi, & ! INOUT
971 'Inverse', nlev_M) ! IN
972
973 end if
974
975 !- Insert results in gd and deallocate moemories
976 gd_in(:,:,ControlVariable(UWindID)%kDimStart:ControlVariable(UWindID)%kDimEnd) = psi(:,:,:)
977 gd_in(:,:,ControlVariable(VWindID)%kDimStart:ControlVariable(VWindID)%kDimEnd) = chi(:,:,:)
978
979 deallocate(chi)
980 deallocate(psi)
981 deallocate(vphy)
982 deallocate(uphy)
983
984 end if
985
986 end if
987
988 !
989 !- 3. Multiply by the grid point standard deviations
990 !
991
992 !$OMP PARALLEL DO PRIVATE(var,kstart,kend)
993 do var = 1, nControlVariable
994 kstart = ControlVariable(var)%kDimStart
995 kend = ControlVariable(var)%kDimEnd
996 gd_in(:,:,kstart:kend) = gd_in(:,:,kstart:kend) * ControlVariable(var)%GpStdDev(myLonBeg:myLonEnd,myLatBeg:myLatEnd,:)
997 end do
998 !$OMP END PARALLEL DO
999
1000 !
1001 !- 2. Grid Point Space -> Spectral Space
1002 !
1003 kind = 'GridPointToSpectral'
1004 call lst_VarTransform(lst_bhi, & ! IN
1005 hiControlVector_out, & ! OUT
1006 gd_in, & ! IN
1007 kind, nksdim ) ! IN
1008
1009 !
1010 !- 1. B^1/2 * xi (in spectral space)
1011 !
1012 call lbhi_bSqrtXi( hiControlVector_out ) ! INOUT
1013
1014 end subroutine lbhi_cv2gdAdj
1015
1016 !--------------------------------------------------------------------------
1017 ! lbhi_bSqrtXi
1018 !--------------------------------------------------------------------------
1019 subroutine lbhi_bSqrtXi(hiControlVector_in)
1020 implicit none
1021
1022 ! Arguments:
1023 real(8), intent(inout) :: hiControlVector_in(lst_bhi%nla, lst_bhi%nphase, nksdim)
1024
1025 ! Locals:
1026 real(8), allocatable :: sp_in (:,:,:)
1027 real(8), allocatable :: sp_out(:,:,:)
1028 integer :: totwvnb, e, k, ila
1029 integer :: m, n, lda, ldb, ldc
1030
1031 !
1032 !- 1. B^1/2 * xi (in spectral space)
1033 !
1034 do totwvnb = 0, trunc
1035
1036 if ( lst_bhi%nePerK(totwvnb) == 0 ) then
1037 cycle
1038 end if
1039
1040 allocate( sp_in (nksdim,lst_bhi%nphase,lst_bhi%nePerK(totwvnb)) )
1041 allocate( sp_out(nksdim,lst_bhi%nphase,lst_bhi%nePerK(totwvnb)) )
1042
1043 !- 1.1 Select spectral elements associated with the total wavenumber
1044 !$OMP PARALLEL DO PRIVATE(e,ila,k)
1045 do e = 1, lst_bhi%nePerK(totwvnb)
1046 ila = lst_bhi%ilaFromEK(e,totwvnb)
1047 do k = 1, nksdim
1048 sp_in(k,1:lst_bhi%nphase,e) = hiControlVector_in(ila,1:lst_bhi%nphase,k)
1049 end do
1050 end do
1051 !$OMP END PARALLEL DO
1052
1053 !- 1.2 Compute bsqrt * sp_in using DGEMM
1054
1055 ! For documentation on dgemm, see: http://www.netlib.org/blas/dgemm.f
1056 ! Matrix A = BSQRT(:,:,totwvnb)
1057 ! Matrix B = SP_IN
1058 ! Matrix C = SP_OUT
1059 m = nksdim
1060 n = lst_bhi%nphase * lst_bhi%nePerK(totwvnb)
1061 k = nksdim
1062 lda = nksdim
1063 ldb = nksdim
1064 ldc = nksdim
1065
1066 call dgemm( 'N', 'N', m, n, k, 1.d0, & ! IN
1067 bsqrt(:,:,totwvnb), lda, sp_in, ldb, 0.d0, & ! IN
1068 sp_out, & ! OUT
1069 ldc ) ! IN
1070
1071 !- 1.3 Replace sp values with output matrix
1072 !$OMP PARALLEL DO PRIVATE(e,ila,k)
1073 do e = 1, lst_bhi%nePerK(totwvnb)
1074 ila = lst_bhi%ilaFromEK(e,totwvnb)
1075 do k = 1, nksdim
1076 hiControlVector_in(ila,1:lst_bhi%nphase,k) = sp_out(k,1:lst_bhi%nphase,e)
1077 end do
1078 end do
1079 !$OMP END PARALLEL DO
1080
1081 deallocate(sp_in)
1082 deallocate(sp_out)
1083
1084 end do ! Total Wavenumber
1085
1086 end subroutine lbhi_bSqrtXi
1087
1088 !--------------------------------------------------------------------------
1089 ! lbhi_cain
1090 !--------------------------------------------------------------------------
1091 SUBROUTINE lbhi_cain(controlVector_in, hiControlVector_out)
1092 implicit none
1093
1094 ! Arguments:
1095 real(8), intent(in) :: controlVector_in(cvDim)
1096 real(8), intent(out) :: hiControlVector_out(lst_bhi%nla,lst_bhi%nphase,nksdim)
1097
1098 ! Locals:
1099 integer :: dim, k, ila, p
1100
1101 dim = 0
1102 hiControlVector_out(:,:,:) = 0.0d0
1103 do k = 1, nksdim
1104 do ila = 1, lst_bhi%nla
1105 do p = 1, lst_bhi%nphase
1106 dim = dim + 1
1107 hiControlVector_out(ila,p,k) = controlVector_in(dim) * lst_bhi%NormFactor(ila,p)
1108 end do
1109 end do
1110 end do
1111
1112 end SUBROUTINE lbhi_cain
1113
1114 !--------------------------------------------------------------------------
1115 ! lbhi_cainAdj
1116 !--------------------------------------------------------------------------
1117 SUBROUTINE lbhi_cainAdj(controlVector_out, hiControlVector_in)
1118 implicit none
1119
1120 ! Arguments:
1121 real(8), intent(out) :: controlVector_out(cvDim)
1122 real(8), intent(in ) :: hiControlVector_in(lst_bhi%nla,lst_bhi%nphase,nksdim)
1123
1124 ! Locals:
1125 integer :: dim, k, ila, p
1126
1127 dim = 0
1128 do k = 1, nksdim
1129 do ila = 1, lst_bhi%nla
1130 do p = 1, lst_bhi%nphase
1131 dim = dim + 1
1132 controlVector_out(dim) = controlVector_out(dim) + &
1133 hiControlVector_in(ila,p,k) * lst_bhi%NormFactorAd(ila,p)
1134 end do
1135 end do
1136 end do
1137
1138 end SUBROUTINE lbhi_cainAdj
1139
1140 !--------------------------------------------------------------------------
1141 ! StatevectorInterface
1142 !--------------------------------------------------------------------------
1143 subroutine StatevectorInterface(statevector, gd, Direction)
1144 implicit none
1145
1146 ! Arguments:
1147 type(struct_gsv), intent(inout) :: statevector
1148 real(8), intent(inout) :: gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nksdim)
1149 character(len=*), intent(in) :: Direction
1150
1151 ! Locals:
1152 integer :: var
1153 integer :: kgdStart, kgdEnd, i, j, k, kgd, nlev
1154 real(4), pointer :: field_r4(:,:,:)
1155 real(8), pointer :: field_r8(:,:,:)
1156 character(len=4 ) :: varname
1157 logical :: ToStateVector
1158
1159 select case ( trim(Direction) )
1160 case ('ToStateVector')
1161 ToStateVector = .true.
1162 case ('FromStateVector')
1163 ToStateVector = .false.
1164 case default
1165 write(*,*)
1166 write(*,*) 'StatevectorInterface: Unknown Direction ', trim(Direction)
1167 call utl_abort('StatevectorInterface')
1168 end select
1169
1170 do var = 1, nControlVariable
1171
1172 varname = ControlVariable(var)%nomvar(cv_model)
1173
1174 if (.not. gsv_varExist(statevector,varname) ) then
1175 write(*,*)
1176 write(*,*) 'StatevectorInterface: The following variable is MISSING in GridStateVector'
1177 write(*,*) varname
1178 call utl_abort('StatevectorInterface')
1179 end if
1180
1181 if (gsv_getDataKind(statevector) == 4) then
1182 call gsv_getField(statevector,field_r4,varname)
1183 else
1184 call gsv_getField(statevector,field_r8,varname)
1185 end if
1186
1187 kgdStart = ControlVariable(var)%kDimStart
1188 kgdEnd = ControlVariable(var)%kDimEnd
1189
1190 nlev = gsv_getNumLev(statevector,vnl_varLevelFromVarname(varname))
1191 if ( kgdEnd - kgdStart + 1 /= nlev ) then
1192 write(*,*)
1193 write(*,*) 'StatevectorInterface: Number of vertical level mismatch'
1194 write(*,*) kgdEnd - kgdStart + 1, nlev
1195 call utl_abort('StatevectorInterface')
1196 end if
1197
1198 if ( ToStateVector ) then
1199 if (gsv_getDataKind(statevector) == 4) then
1200 !$OMP PARALLEL DO PRIVATE(j,kgd,k,i)
1201 do kgd = kgdStart, kgdEnd
1202 k = kgd - kgdStart + 1
1203 do j = myLatBeg, myLatEnd
1204 do i = myLonBeg, myLonEnd
1205 field_r4(i,j,k) = gd(i,j,kgd)
1206 end do
1207 end do
1208 end do
1209 !$OMP END PARALLEL DO
1210 else
1211 !$OMP PARALLEL DO PRIVATE(j,kgd,k,i)
1212 do kgd = kgdStart, kgdEnd
1213 k = kgd - kgdStart + 1
1214 do j = myLatBeg, myLatEnd
1215 do i = myLonBeg, myLonEnd
1216 field_r8(i,j,k) = gd(i,j,kgd)
1217 end do
1218 end do
1219 end do
1220 !$OMP END PARALLEL DO
1221 end if
1222 else
1223 if (gsv_getDataKind(statevector) == 4) then
1224 !$OMP PARALLEL DO PRIVATE(j,kgd,k,i)
1225 do kgd = kgdStart, kgdEnd
1226 k = kgd - kgdStart + 1
1227 do j = myLatBeg, myLatEnd
1228 do i = myLonBeg, myLonEnd
1229 gd(i,j,kgd) = field_r4(i,j,k)
1230 end do
1231 end do
1232 end do
1233 !$OMP END PARALLEL DO
1234 else
1235 !$OMP PARALLEL DO PRIVATE(j,kgd,k,i)
1236 do kgd = kgdStart, kgdEnd
1237 k = kgd - kgdStart + 1
1238 do j = myLatBeg, myLatEnd
1239 do i = myLonBeg, myLonEnd
1240 gd(i,j,kgd) = field_r8(i,j,k)
1241 end do
1242 end do
1243 end do
1244 !$OMP END PARALLEL DO
1245 end if
1246 end if
1247 end do
1248
1249 end subroutine StatevectorInterface
1250
1251 !--------------------------------------------------------------------------
1252 ! lbhi_reduceToMPILocal
1253 !--------------------------------------------------------------------------
1254 SUBROUTINE lbhi_reduceToMPILocal(cv_mpilocal,cv_mpiglobal)
1255 implicit none
1256
1257 ! Arguments:
1258 real(8), intent(out) :: cv_mpilocal(cvDim)
1259 real(8), intent(in) :: cv_mpiglobal(:)
1260
1261 ! Locals:
1262 real(8), allocatable :: cv_allmaxmpilocal(:,:)
1263 integer, allocatable :: cvDim_allMpilocal(:), displs(:)
1264 integer, allocatable :: ilaGlobal(:), allnlaLocal(:)
1265 integer, allocatable :: allilaGlobal(:,:)
1266 integer :: k, ila, p, ila_mpiglobal, jdim_mpilocal, jdim_mpiglobal
1267 integer :: ier, nlaMax, cvDim_maxmpilocal, jproc
1268
1269 call rpn_comm_allreduce(cvDim, cvDim_maxmpilocal, &
1270 1,"MPI_INTEGER","MPI_MAX","GRID",ier)
1271
1272 allocate(cvDim_allMpiLocal(mmpi_nprocs))
1273
1274 call rpn_comm_allgather(cvDim ,1,"mpi_integer", &
1275 cvDim_allMpiLocal,1,"mpi_integer","GRID",ier)
1276
1277 call rpn_comm_allreduce(lst_bhi%nla,nlaMax,1,"mpi_integer","mpi_max","GRID",ier)
1278
1279 if (mmpi_myid == 0) then
1280 allocate(allnlaLocal(mmpi_nprocs))
1281 allocate(allilaGlobal(nlaMax,mmpi_nprocs))
1282 else
1283 allocate(allnlaLocal(1))
1284 allocate(allilaGlobal(1,1))
1285 end if
1286
1287 allocate(ilaGlobal(nlaMax))
1288 ilaGlobal(:) = -1
1289 ilaGlobal(1:lst_bhi%nla) = lst_bhi%ilaGlobal(:)
1290
1291 call rpn_comm_gather(lst_bhi%nla, 1, "mpi_integer", &
1292 allnlaLocal, 1, "mpi_integer", 0, "GRID", ier)
1293 call rpn_comm_gather(ilaGlobal , nlaMax, "mpi_integer", &
1294 allilaGlobal, nlaMax, "mpi_integer",0 ,"GRID", ier)
1295
1296 deallocate(ilaGlobal)
1297
1298 ! assign part of mpiglobal vector from current mpi process
1299 if (mmpi_myid == 0) then
1300
1301 allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
1302
1303 !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,k,ila,p,ila_mpiglobal,jdim_mpiglobal)
1304 do jproc = 0, (mmpi_nprocs-1)
1305 cv_allmaxmpilocal(:,jproc+1) = 0.d0
1306
1307 do k = 1, nksdim
1308 do ila = 1, allnlaLocal(jproc+1)
1309 do p = 1, lst_bhi%nphase
1310
1311 jdim_mpilocal = ( (k-1) * allnlaLocal(jproc+1) * lst_bhi%nphase ) + &
1312 ( (ila-1) * lst_bhi%nphase ) + p
1313
1314 ila_mpiglobal = allilaGlobal(ila,jproc+1)
1315 if ( ila_mpiglobal <= 0 ) then
1316 write(*,*) 'lbhi_reduceToMPILocal: invalid ila_mpiglobal index ', ila_mpiglobal
1317 call utl_abort('lbhi_reduceToMPILocal')
1318 end if
1319
1320 jdim_mpiglobal = ( (k-1) * lst_bhi%nlaGlobal * lst_bhi%nphase ) + &
1321 ( (ila_mpiglobal-1) * lst_bhi%nphase ) + p
1322
1323 if (jdim_mpilocal > cvDim_allMpiLocal(jproc+1)) then
1324 write(*,*)
1325 write(*,*) 'ERROR: jdim_mpilocal > cvDim_allMpiLocal(jproc+1)', jdim_mpilocal, cvDim_allMpiLocal(jproc+1)
1326 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1327 call utl_abort('lbhi_reduceToMPILocal')
1328 end if
1329 if (jdim_mpiglobal > cvDim_mpiglobal) then
1330 write(*,*)
1331 write(*,*) 'ERROR: jdim_mpiglobal > cvDim_mpiglobal', jdim_mpiglobal, cvDim_mpiglobal
1332 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1333 call utl_abort('lbhi_reduceToMPILocal')
1334 end if
1335
1336 cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal)
1337
1338 end do
1339 end do
1340 end do
1341 end do
1342 !$OMP END PARALLEL DO
1343
1344 else
1345 allocate(cv_allmaxmpilocal(1,1))
1346 end if
1347
1348 deallocate(allnlaLocal)
1349 deallocate(allilaGlobal)
1350
1351 !- Distribute
1352 allocate(displs(mmpi_nprocs))
1353 !$OMP PARALLEL DO PRIVATE(jproc)
1354 do jproc = 0, (mmpi_nprocs-1)
1355 displs(jproc+1) = jproc*cvDim_maxMpiLocal ! displacement wrt cv_allMaxMpiLocal from which
1356 ! to take the outgoing data to process jproc
1357 end do
1358 !$OMP END PARALLEL DO
1359
1360 call rpn_comm_scatterv(cv_allMaxMpiLocal, cvDim_allMpiLocal, displs, "mpi_double_precision", &
1361 cv_mpiLocal , cvDim , "mpi_double_precision", &
1362 0, "GRID", ier)
1363
1364 deallocate(displs)
1365 deallocate(cv_allMaxMpiLocal)
1366 deallocate(cvDim_allMpiLocal)
1367
1368
1369 END SUBROUTINE lbhi_reduceToMPILocal
1370
1371 !--------------------------------------------------------------------------
1372 ! lbhi_reduceToMPILocal_r4
1373 !--------------------------------------------------------------------------
1374 SUBROUTINE lbhi_reduceToMPILocal_r4(cv_mpilocal,cv_mpiglobal)
1375 implicit none
1376
1377 ! Arguments:
1378 real(4), intent(out) :: cv_mpilocal(cvDim)
1379 real(4), intent(in) :: cv_mpiglobal(:)
1380
1381 ! Locals:
1382 real(4), allocatable :: cv_allmaxmpilocal(:,:)
1383 integer, allocatable :: cvDim_allMpilocal(:), displs(:)
1384 integer, allocatable :: ilaGlobal(:), allnlaLocal(:)
1385 integer, allocatable :: allilaGlobal(:,:)
1386 integer :: k, ila, p, ila_mpiglobal, jdim_mpilocal, jdim_mpiglobal
1387 integer :: ier, nlaMax, cvDim_maxmpilocal, jproc
1388
1389 call rpn_comm_allreduce(cvDim, cvDim_maxmpilocal, &
1390 1,"MPI_INTEGER","MPI_MAX","GRID",ier)
1391
1392 allocate(cvDim_allMpiLocal(mmpi_nprocs))
1393
1394 call rpn_comm_allgather(cvDim ,1,"mpi_integer", &
1395 cvDim_allMpiLocal,1,"mpi_integer","GRID",ier)
1396
1397 call rpn_comm_allreduce(lst_bhi%nla,nlaMax,1,"mpi_integer","mpi_max","GRID",ier)
1398
1399 if (mmpi_myid == 0) then
1400 allocate(allnlaLocal(mmpi_nprocs))
1401 allocate(allilaGlobal(nlaMax,mmpi_nprocs))
1402 else
1403 allocate(allnlaLocal(1))
1404 allocate(allilaGlobal(1,1))
1405 end if
1406
1407 allocate(ilaGlobal(nlaMax))
1408 ilaGlobal(:) = -1
1409 ilaGlobal(1:lst_bhi%nla) = lst_bhi%ilaGlobal(:)
1410
1411 call rpn_comm_gather(lst_bhi%nla, 1, "mpi_integer", &
1412 allnlaLocal, 1, "mpi_integer", 0, "GRID", ier)
1413 call rpn_comm_gather(ilaGlobal , nlaMax, "mpi_integer", &
1414 allilaGlobal, nlaMax, "mpi_integer",0 ,"GRID", ier)
1415
1416 deallocate(ilaGlobal)
1417
1418 ! assign part of mpiglobal vector from current mpi process
1419 if (mmpi_myid == 0) then
1420
1421 allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
1422
1423 !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,k,ila,p,ila_mpiglobal,jdim_mpiglobal)
1424 do jproc = 0, (mmpi_nprocs-1)
1425 cv_allmaxmpilocal(:,jproc+1) = 0.d0
1426
1427 do k = 1, nksdim
1428 do ila = 1, allnlaLocal(jproc+1)
1429 do p = 1, lst_bhi%nphase
1430
1431 jdim_mpilocal = ( (k-1) * allnlaLocal(jproc+1) * lst_bhi%nphase ) + &
1432 ( (ila-1) * lst_bhi%nphase ) + p
1433
1434 ila_mpiglobal = allilaGlobal(ila,jproc+1)
1435 if ( ila_mpiglobal <= 0 ) then
1436 write(*,*) 'lbhi_reduceToMPILocal: invalid ila_mpiglobal index ', ila_mpiglobal
1437 call utl_abort('lbhi_reduceToMPILocal')
1438 end if
1439
1440 jdim_mpiglobal = ( (k-1) * lst_bhi%nlaGlobal * lst_bhi%nphase ) + &
1441 ( (ila_mpiglobal-1) * lst_bhi%nphase ) + p
1442
1443 if (jdim_mpilocal > cvDim_allMpiLocal(jproc+1)) then
1444 write(*,*)
1445 write(*,*) 'ERROR: jdim_mpilocal > cvDim_allMpiLocal(jproc+1)', jdim_mpilocal, cvDim_allMpiLocal(jproc+1)
1446 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1447 call utl_abort('lbhi_reduceToMPILocal')
1448 end if
1449 if (jdim_mpiglobal > cvDim_mpiglobal) then
1450 write(*,*)
1451 write(*,*) 'ERROR: jdim_mpiglobal > cvDim_mpiglobal', jdim_mpiglobal, cvDim_mpiglobal
1452 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1453 call utl_abort('lbhi_reduceToMPILocal')
1454 end if
1455
1456 cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal)
1457
1458 end do
1459 end do
1460 end do
1461 end do
1462 !$OMP END PARALLEL DO
1463
1464 else
1465 allocate(cv_allmaxmpilocal(1,1))
1466 end if
1467
1468 deallocate(allnlaLocal)
1469 deallocate(allilaGlobal)
1470
1471 !- Distribute
1472 allocate(displs(mmpi_nprocs))
1473 !$OMP PARALLEL DO PRIVATE(jproc)
1474 do jproc = 0, (mmpi_nprocs-1)
1475 displs(jproc+1) = jproc*cvDim_maxMpiLocal ! displacement wrt cv_allMaxMpiLocal from which
1476 ! to take the outgoing data to process jproc
1477 end do
1478 !$OMP END PARALLEL DO
1479
1480 call rpn_comm_scatterv(cv_allMaxMpiLocal, cvDim_allMpiLocal, displs, "mpi_real4", &
1481 cv_mpiLocal , cvDim , "mpi_real4", &
1482 0, "GRID", ier)
1483
1484 deallocate(displs)
1485 deallocate(cv_allMaxMpiLocal)
1486 deallocate(cvDim_allMpiLocal)
1487
1488
1489 END SUBROUTINE lbhi_reduceToMPILocal_r4
1490
1491 !--------------------------------------------------------------------------
1492 ! lbhi_expandToMPIGlobal
1493 !--------------------------------------------------------------------------
1494 SUBROUTINE lbhi_expandToMPIGlobal(cv_mpilocal,cv_mpiglobal)
1495 implicit none
1496
1497 ! Arguments:
1498 real(8), intent(in) :: cv_mpilocal(cvDim)
1499 real(8), intent(out) :: cv_mpiglobal(:)
1500
1501 ! Locals:
1502 real(8), allocatable :: cv_maxmpilocal(:)
1503 real(8), pointer :: cv_allmaxmpilocal(:,:) => null()
1504 integer, allocatable :: cvDim_allMpilocal(:)
1505 integer, allocatable :: ilaGlobal(:), allnlaLocal(:)
1506 integer, allocatable :: allilaGlobal(:,:)
1507 integer :: k, ila, p, ila_mpiglobal, jdim_mpilocal, jdim_mpiglobal
1508 integer :: ier, nlaMax, cvDim_maxmpilocal, jproc
1509
1510 !
1511 !- 1. Gather all local control vectors onto mpi task 0
1512 !
1513 allocate(cvDim_allMpiLocal(mmpi_nprocs))
1514 call rpn_comm_allgather(cvDim ,1,"mpi_integer", &
1515 cvDim_allMpiLocal,1,"mpi_integer","GRID",ier)
1516
1517 call rpn_comm_allreduce(cvDim,cvDim_maxmpilocal,1,"mpi_integer","mpi_max","GRID",ier)
1518
1519 allocate(cv_maxmpilocal(cvDim_maxmpilocal))
1520
1521 cv_maxmpilocal(:) = 0.0d0
1522 cv_maxmpilocal(1:cvDim) = cv_mpilocal(1:cvDim)
1523
1524 nullify(cv_allmaxmpilocal)
1525 if (mmpi_myid == 0) then
1526 allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
1527 else
1528 allocate(cv_allmaxmpilocal(1,1))
1529 end if
1530
1531 call rpn_comm_gather(cv_maxmpilocal, cvDim_maxmpilocal, "mpi_double_precision", &
1532 cv_allmaxmpilocal, cvDim_maxmpilocal, "mpi_double_precision", 0, "GRID", ier )
1533
1534 deallocate(cv_maxmpilocal)
1535
1536 !
1537 !- 2. Reorganize gathered mpilocal control vectors into the mpiglobal control vector
1538 !
1539
1540 call rpn_comm_allreduce(lst_bhi%nla,nlaMax,1,"mpi_integer","mpi_max","GRID",ier)
1541
1542 if (mmpi_myid == 0) then
1543 allocate(allnlaLocal(mmpi_nprocs))
1544 allocate(allilaGlobal(nlaMax,mmpi_nprocs))
1545 else
1546 allocate(allnlaLocal(1))
1547 allocate(allilaGlobal(1,1))
1548 end if
1549
1550 allocate(ilaGlobal(nlaMax))
1551 ilaGlobal(:) = -1
1552 ilaGlobal(1:lst_bhi%nla) = lst_bhi%ilaGlobal(:)
1553
1554 call rpn_comm_gather(lst_bhi%nla, 1, "mpi_integer", &
1555 allnlaLocal, 1, "mpi_integer", 0, "GRID", ier)
1556 call rpn_comm_gather(ilaGlobal , nlaMax, "mpi_integer", &
1557 allilaGlobal, nlaMax, "mpi_integer",0 ,"GRID", ier)
1558
1559 deallocate(ilaGlobal)
1560
1561 if (mmpi_myid == 0) then
1562 cv_mpiglobal(:) = 0.0d0
1563
1564 !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,k,ila,p,ila_mpiglobal,jdim_mpiglobal)
1565 do jproc = 0, (mmpi_nprocs-1)
1566 do k = 1, nksdim
1567 do ila = 1, allnlaLocal(jproc+1)
1568 do p = 1, lst_bhi%nphase
1569
1570 jdim_mpilocal = ( (k-1) * allnlaLocal(jproc+1) * lst_bhi%nphase ) + &
1571 ( (ila-1) * lst_bhi%nphase ) + p
1572
1573 ila_mpiglobal = allilaGlobal(ila,jproc+1)
1574 if ( ila_mpiglobal <= 0 ) then
1575 write(*,*) 'lbhi_expandToMPIGlobal: invalid ila_mpiglobal index ', ila_mpiglobal
1576 call utl_abort('lbhi_expandToMPIGlobal')
1577 end if
1578
1579 jdim_mpiglobal = ( (k-1) * lst_bhi%nlaGlobal * lst_bhi%nphase ) + &
1580 ( (ila_mpiglobal-1) * lst_bhi%nphase ) + p
1581
1582 if (jdim_mpilocal > cvDim_allMpiLocal(jproc+1)) then
1583 write(*,*)
1584 write(*,*) 'ERROR: jdim_mpilocal > cvDim_allMpiLocal(jproc+1)', jdim_mpilocal, cvDim_allMpiLocal(jproc+1)
1585 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1586 call utl_abort('lbhi_expandToMPIGlobal')
1587 end if
1588 if (jdim_mpiglobal > cvDim_mpiglobal) then
1589 write(*,*)
1590 write(*,*) 'ERROR: jdim_mpiglobal > cvDim_mpiglobal', jdim_mpiglobal, cvDim_mpiglobal
1591 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1592 call utl_abort('lbhi_expandToMPIGlobal')
1593 end if
1594
1595 cv_mpiglobal(jdim_mpiglobal) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
1596
1597 end do
1598 end do
1599 end do
1600 end do
1601 !$OMP END PARALLEL DO
1602
1603 end if
1604
1605 deallocate(allnlaLocal)
1606 deallocate(allilaGlobal)
1607 deallocate(cv_allmaxmpilocal)
1608 deallocate(cvDim_allMpiLocal)
1609
1610 end SUBROUTINE lbhi_expandToMPIGlobal
1611
1612 !--------------------------------------------------------------------------
1613 ! lbhi_expandToMPIGlobal_r4
1614 !--------------------------------------------------------------------------
1615 SUBROUTINE lbhi_expandToMPIGlobal_r4(cv_mpilocal,cv_mpiglobal)
1616 implicit none
1617
1618 ! Arguments:
1619 real(4), intent(in) :: cv_mpilocal(cvDim)
1620 real(4), intent(out) :: cv_mpiglobal(:)
1621
1622 ! Locals:
1623 real(4), allocatable :: cv_maxmpilocal(:)
1624 real(4), pointer :: cv_allmaxmpilocal(:,:) => null()
1625 integer, allocatable :: cvDim_allMpilocal(:)
1626 integer, allocatable :: ilaGlobal(:), allnlaLocal(:)
1627 integer, allocatable :: allilaGlobal(:,:)
1628 integer :: k, ila, p, ila_mpiglobal, jdim_mpilocal, jdim_mpiglobal
1629 integer :: ier, nlaMax, cvDim_maxmpilocal, jproc
1630
1631 !
1632 !- 1. Gather all local control vectors onto mpi task 0
1633 !
1634 allocate(cvDim_allMpiLocal(mmpi_nprocs))
1635 call rpn_comm_allgather(cvDim ,1,"mpi_integer", &
1636 cvDim_allMpiLocal,1,"mpi_integer","GRID",ier)
1637
1638 call rpn_comm_allreduce(cvDim,cvDim_maxmpilocal,1,"mpi_integer","mpi_max","GRID",ier)
1639
1640 allocate(cv_maxmpilocal(cvDim_maxmpilocal))
1641
1642 cv_maxmpilocal(:) = 0.0d0
1643 cv_maxmpilocal(1:cvDim) = cv_mpilocal(1:cvDim)
1644
1645 nullify(cv_allmaxmpilocal)
1646 if (mmpi_myid == 0) then
1647 allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
1648 else
1649 allocate(cv_allmaxmpilocal(1,1))
1650 end if
1651
1652 call rpn_comm_gather(cv_maxmpilocal, cvDim_maxmpilocal, "mpi_real4", &
1653 cv_allmaxmpilocal, cvDim_maxmpilocal, "mpi_real4", 0, "GRID", ier )
1654
1655 deallocate(cv_maxmpilocal)
1656
1657 !
1658 !- 2. Reorganize gathered mpilocal control vectors into the mpiglobal control vector
1659 !
1660
1661 call rpn_comm_allreduce(lst_bhi%nla,nlaMax,1,"mpi_integer","mpi_max","GRID",ier)
1662
1663 if (mmpi_myid == 0) then
1664 allocate(allnlaLocal(mmpi_nprocs))
1665 allocate(allilaGlobal(nlaMax,mmpi_nprocs))
1666 else
1667 allocate(allnlaLocal(1))
1668 allocate(allilaGlobal(1,1))
1669 end if
1670
1671 allocate(ilaGlobal(nlaMax))
1672 ilaGlobal(:) = -1
1673 ilaGlobal(1:lst_bhi%nla) = lst_bhi%ilaGlobal(:)
1674
1675 call rpn_comm_gather(lst_bhi%nla, 1, "mpi_integer", &
1676 allnlaLocal, 1, "mpi_integer", 0, "GRID", ier)
1677 call rpn_comm_gather(ilaGlobal , nlaMax, "mpi_integer", &
1678 allilaGlobal, nlaMax, "mpi_integer",0 ,"GRID", ier)
1679
1680 deallocate(ilaGlobal)
1681
1682 if (mmpi_myid == 0) then
1683 cv_mpiglobal(:) = 0.0d0
1684
1685 !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,k,ila,p,ila_mpiglobal,jdim_mpiglobal)
1686 do jproc = 0, (mmpi_nprocs-1)
1687 do k = 1, nksdim
1688 do ila = 1, allnlaLocal(jproc+1)
1689 do p = 1, lst_bhi%nphase
1690
1691 jdim_mpilocal = ( (k-1) * allnlaLocal(jproc+1) * lst_bhi%nphase ) + &
1692 ( (ila-1) * lst_bhi%nphase ) + p
1693
1694 ila_mpiglobal = allilaGlobal(ila,jproc+1)
1695 if ( ila_mpiglobal <= 0 ) then
1696 write(*,*) 'lbhi_expandToMPIGlobal: invalid ila_mpiglobal index ', ila_mpiglobal
1697 call utl_abort('lbhi_expandToMPIGlobal')
1698 end if
1699
1700 jdim_mpiglobal = ( (k-1) * lst_bhi%nlaGlobal * lst_bhi%nphase ) + &
1701 ( (ila_mpiglobal-1) * lst_bhi%nphase ) + p
1702
1703 if (jdim_mpilocal > cvDim_allMpiLocal(jproc+1)) then
1704 write(*,*)
1705 write(*,*) 'ERROR: jdim_mpilocal > cvDim_allMpiLocal(jproc+1)', jdim_mpilocal, cvDim_allMpiLocal(jproc+1)
1706 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1707 call utl_abort('lbhi_expandToMPIGlobal')
1708 end if
1709 if (jdim_mpiglobal > cvDim_mpiglobal) then
1710 write(*,*)
1711 write(*,*) 'ERROR: jdim_mpiglobal > cvDim_mpiglobal', jdim_mpiglobal, cvDim_mpiglobal
1712 write(*,*) ' proc, k, ila, p = ',jproc,k,ila,p
1713 call utl_abort('lbhi_expandToMPIGlobal')
1714 end if
1715
1716 cv_mpiglobal(jdim_mpiglobal) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
1717
1718 end do
1719 end do
1720 end do
1721 end do
1722 !$OMP END PARALLEL DO
1723
1724 end if
1725
1726 deallocate(allnlaLocal)
1727 deallocate(allilaGlobal)
1728 deallocate(cv_allmaxmpilocal)
1729 deallocate(cvDim_allMpiLocal)
1730
1731 end SUBROUTINE lbhi_expandToMPIGlobal_r4
1732
1733 !--------------------------------------------------------------------------
1734 ! lbhi_Finalize
1735 !--------------------------------------------------------------------------
1736 subroutine lbhi_Finalize
1737 implicit none
1738
1739 ! Locals:
1740 integer :: var
1741
1742 if (initialized) then
1743 deallocate(bsqrt)
1744 do var = 1, nControlVariable
1745 deallocate(ControlVariable(var)%GpStdDev)
1746 deallocate(ControlVariable(var)%ip1 )
1747 end do
1748 end if
1749
1750 end subroutine lbhi_Finalize
1751
1752end module lamBmatrixHI_mod