bMatrixHI_mod sourceΒΆ

   1MODULE bMatrixHI_mod
   2  ! MODULE bMatrixHI_mod (prefix='bhi' category='2. B and R matrices')
   3  !
   4  !:Purpose:  Performs transformation from control vector to analysis increment 
   5  !           (and adjoint transformation) using the background-error covariance
   6  !           matrix based on homogeneous and isotropic correlations. This is
   7  !           the Global version. A separate module exists for limited-area applications.
   8  !
   9  use midasMpi_mod
  10  use earthConstants_mod
  11  use gridStateVector_mod
  12  use globalSpectralTransform_mod
  13  use horizontalCoord_mod
  14  use verticalCoord_mod
  15  use timeCoord_mod
  16  use varNameList_mod
  17  use utilities_mod
  18  use gridVariableTransforms_mod
  19  use interpolation_mod
  20  use calcHeightAndPressure_mod
  21  implicit none
  22  save
  23  private
  24
  25  ! public procedures
  26  public :: bhi_Setup,bhi_BSqrt,bhi_BSqrtAd,bhi_Finalize,bhi_expandToMPIglobal,bhi_expandToMPIglobal_r4,bhi_reduceToMPIlocal,bhi_reduceToMPIlocal_r4
  27  public :: bhi_getScaleFactor,bhi_truncateCV
  28
  29
  30  logical             :: initialized = .false.
  31  integer             :: nj_l,ni_l
  32  integer             :: AnalGridID ! EZscintID
  33  integer             :: nlev_M,nlev_T,nlev_T_even,nkgdim,nkgdim2,nkgdimSqrt
  34  integer             :: nla_mpiglobal,nla_mpilocal
  35  integer             :: cvDim_mpilocal,cvDim_mpiglobal
  36  integer             :: gstID, gstID2
  37  integer             :: nlev_bdl
  38  type(struct_vco),pointer :: vco_anl
  39
  40  real(8),allocatable :: tantheta(:,:)
  41  real(8),allocatable :: PtoT(:,:,:)
  42
  43  real(8),pointer     :: rgsig(:,:)
  44  real(8),pointer     :: rgsiguu(:,:),rgsigvv(:,:),rgsigtt(:,:),rgsigtb(:,:),rgsigq(:,:)
  45  real(8),pointer     :: rgsigps(:),rgsigpsb(:)
  46  real(8),allocatable :: tgstdbg(:,:)
  47
  48  real(8),allocatable :: corns(:,:,:)
  49  real(8),allocatable :: rstddev(:,:)
  50
  51  ! namelist variables:
  52  integer             :: ntrunc                          ! spectral trunction
  53  real(8)             :: scaleFactor(vco_maxNumLevels)   ! scale factor applied to variances (all variables)
  54  real(8)             :: scaleFactorLQ(vco_maxNumLevels) ! scale factor applied to humidity
  55  real(8)             :: scaleFactorCC(vco_maxNumLevels) ! scale factor applied to velocity potential
  56  logical             :: scaleTG                         ! scale factor applied to skin temperature
  57  logical             :: TweakTG                         ! adjust skin temp variance based on land-sea mask and sea ice
  58  logical             :: ReadWrite_sqrt                  ! choose to read or write the sqrt of correlations
  59  logical             :: squareSqrt                      ! choose to use the 'square' formulation of corr matrix (not used)
  60  character(len=4)    :: stddevMode                      ! can be 'GD2D' or 'SP2D'
  61  integer             :: numModeZero                     ! number of eigenmodes to set to zero
  62
  63  ! constants
  64  real(8)             :: rcscltg(1)=100000.d0
  65  real(8)             :: rlimsuptg=3.0d0
  66  logical             :: llimtg=.true.
  67  integer             :: nulbgst=0
  68  integer             :: nLevPtoT
  69  real(8)             :: rvlocbalt   = 6.0d0
  70  real(8)             :: rvlocpsi    = 6.0d0
  71  real(8)             :: rvlocchi    = 6.0d0
  72  real(8)             :: rvlocpsitt  = 6.0d0
  73  real(8)             :: rvlocunbalt = 4.0d0
  74  real(8)             :: rvloclq     = 4.0d0
  75  real(8)             :: rlimlv_bdl  = 85000.0d0
  76
  77  ! this should come from state vector object
  78  integer             :: numvar3d
  79  integer             :: numvar2d
  80  integer             :: nspositVO 
  81  integer             :: nspositDI 
  82  integer             :: nspositTT 
  83  integer             :: nspositQ
  84  integer             :: nspositPS 
  85  integer             :: nspositTG
  86
  87  real(8), pointer    :: pressureProfile_M(:),pressureProfile_T(:)
  88
  89  integer             :: mymBeg,mymEnd,mymSkip,mymCount
  90  integer             :: mynBeg,mynEnd,mynSkip,mynCount
  91  integer             :: maxMyNla
  92  integer             :: myLatBeg,myLatEnd
  93  integer             :: myLonBeg,myLonEnd
  94  integer, pointer    :: ilaList_mpiglobal(:)
  95  integer, pointer    :: ilaList_mpilocal(:)
  96
  97  integer,external    :: get_max_rss
  98
  99
 100CONTAINS
 101
 102  SUBROUTINE BHI_setup(hco_in,vco_in,CVDIM_OUT, mode_opt)
 103    implicit none
 104
 105    ! Arguments:
 106    type(struct_hco), pointer,  intent(in)  :: hco_in
 107    type(struct_vco), pointer,  intent(in)  :: vco_in
 108    integer                  ,  intent(out) :: cvDim_out
 109    character(len=*), optional, intent(in)  :: mode_opt
 110
 111    ! Locals:
 112    character(len=15) :: bhi_mode
 113    integer :: jlev, nulnam, ierr, fnom, fclos, fstouv, fstfrm
 114    integer :: jm, jn, latPerPE, lonPerPE, latPerPEmax, lonPerPEmax, Vcode_anl
 115    logical :: llfound, lExists
 116    real(8) :: zps
 117    type(struct_vco),pointer :: vco_file => null()
 118    character(len=8) :: bFileName = './bgcov'
 119
 120    NAMELIST /NAMBHI/ntrunc,scaleFactor,scaleFactorLQ,scaleFactorCC,scaleTG,numModeZero,squareSqrt,TweakTG,ReadWrite_sqrt,stddevMode
 121
 122    if(mmpi_myid == 0) write(*,*) 'bhi_setup: starting'
 123    if(mmpi_myid == 0) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 124
 125    if ( present(mode_opt) ) then
 126       if ( trim(mode_opt) == 'Analysis' .or. trim(mode_opt) == 'BackgroundCheck') then
 127         bhi_mode = trim(mode_opt)
 128         if(mmpi_myid == 0) write(*,*)
 129         if(mmpi_myid == 0) write(*,*) 'bmatrixHI: Mode activated = ', trim(bhi_mode)
 130       else
 131          write(*,*)
 132          write(*,*) 'mode = ', trim(mode_opt)
 133          call utl_abort('bmatrixHI: unknown mode')
 134       end if
 135    else
 136       bhi_mode = 'Analysis'
 137       if(mmpi_myid == 0) write(*,*)
 138       if(mmpi_myid == 0) write(*,*) 'bmatrixHI: Analysis mode activated (by default)'
 139    end if
 140
 141    ! default values for namelist variables
 142    ntrunc = 108
 143    scaleFactor(:) = 0.0d0
 144    scaleFactorLQ(:) = 1.0d0
 145    scaleFactorCC(:) = 1.0d0
 146    scaleTG = .true.
 147    numModeZero = 0
 148    squareSqrt = .false.
 149    TweakTG = .false.
 150    ReadWrite_sqrt = .false.
 151    stddevMode = 'SP2D'
 152
 153    nulnam = 0
 154    ierr = fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
 155    read(nulnam,nml=nambhi,iostat=ierr)
 156    if ( ierr /= 0 ) call utl_abort( 'bhi_setup: Error reading namelist' )
 157    if ( mmpi_myid == 0 ) write( *, nml = nambhi )
 158    ierr = fclos( nulnam )
 159
 160    do jlev = 1, vco_maxNumLevels
 161      if( scaleFactor(jlev) > 0.0d0 ) then 
 162        scaleFactor(jlev) = sqrt(scaleFactor(jlev))
 163      else
 164        scaleFactor(jlev) = 0.0d0
 165      endif
 166    enddo
 167
 168    if ( sum(scaleFactor(1:vco_maxNumLevels)) == 0.0d0 ) then
 169      if ( mmpi_myid == 0 ) write(*,*) 'bmatrixHI: scaleFactor=0, skipping rest of setup'
 170      cvdim_out = 0
 171      return
 172    end if
 173
 174    vco_anl => vco_in
 175    nLev_M = vco_anl%nlev_M
 176    nLev_T = vco_anl%nlev_T
 177    ! need an even number of levels for spectral transform (gstID2)
 178    if(mod(nLev_T,2).ne.0) then
 179      nLev_T_even = nLev_T+1
 180    else
 181      nLev_T_even = nLev_T
 182    endif
 183    if(mmpi_myid == 0) write(*,*) 'BHI_setup: nLev_M, nLev_T, nLev_T_even=',nLev_M, nLev_T, nLev_T_even
 184
 185    ! check if analysisgrid and covariance file have the same vertical levels
 186    call vco_SetupFromFile( vco_file,  & ! OUT
 187                            bFileName )  ! IN
 188    if (.not. vco_equal(vco_anl,vco_file)) then
 189      call utl_abort('bmatrixHI: vco from analysisgrid and cov file do not match')
 190    end if
 191
 192    Vcode_anl = vco_anl%Vcode
 193    if(Vcode_anl .ne. 5002 .and. Vcode_anl .ne. 5005) then
 194      write(*,*) 'Vcode_anl = ',Vcode_anl
 195      call utl_abort('bmatrixHI: unknown vertical coordinate type!')
 196    endif
 197
 198    if (.not. (gsv_varExist(varName='TT') .and.  &
 199               gsv_varExist(varName='UU') .and.  &
 200               gsv_varExist(varName='VV') .and.  &
 201               (gsv_varExist(varName='HU').or.gsv_varExist(varName='LQ')) .and.  &
 202               gsv_varExist(varName='P0')) ) then
 203      call utl_abort('bmatrixHI: Some or all weather fields are missing. If it is desired to deactivate the weather assimilation, then all entries of the array SCALEFACTOR in the namelist NAMBHI should be set to zero.')
 204    end if
 205    if (.not. gsv_varExist(varName='TG')) then
 206      write(*,*) 'bmatrixHI: WARNING: The TG field is missing. This must be present when assimilating'
 207      write(*,*) '                    radiance observations'
 208    end if
 209
 210    do jlev = 1, max(nLev_M,nLev_T)
 211      if(scaleFactorLQ(jlev).gt.0.0d0) then 
 212        scaleFactorLQ(jlev) = sqrt(scaleFactorLQ(jlev))
 213      else
 214        scaleFactorLQ(jlev) = 0.0d0
 215      endif
 216    enddo
 217
 218    do jlev = 1, max(nLev_M,nLev_T)
 219      if(scaleFactorCC(jlev).gt.0.0d0) then 
 220        scaleFactorCC(jlev) = sqrt(scaleFactorCC(jlev))
 221      else
 222        scaleFactorCC(jlev) = 0.0d0
 223      endif
 224    enddo
 225
 226    if ( trim(bhi_mode) == 'BackgroundCheck' ) then
 227       cvDim_out = 9999 ! Dummy value > 0 to indicate to the background check (s/r ose_compute_HBHT_ensemble) 
 228                        ! that Bhi is used
 229       return
 230    end if
 231
 232    numvar3d = 4
 233    numvar2d = 2
 234
 235    nLevPtot = nLev_M-1 ! ignore streamfunction at hyb=1, since highly correlated with next level
 236    nspositVO = 1
 237    nspositDI = 1*nLev_M+1
 238    nspositTT = 2*nLev_M+1
 239    nspositQ  = 2*nLev_M+1*nLev_T+1
 240    nspositPS = 2*nLev_M+2*nLev_T+1
 241    nspositTG = 2*nLev_M+2*nLev_T+2
 242    nkgdim = nLev_M*2 + nLev_T*2 + numvar2d
 243    nkgdim2 = nkgdim + nLev_T
 244    if(squareSqrt) then
 245      nkgdimSqrt = nkgdim2
 246    else
 247      nkgdimSqrt = nkgdim
 248    endif
 249    nla_mpiglobal = (ntrunc+1)*(ntrunc+2)/2
 250    
 251    ni_l = hco_in%ni
 252    nj_l = hco_in%nj
 253    AnalGridID = hco_in%EZscintID
 254
 255    gstID  = gst_setup(ni_l,nj_l,ntrunc,nkgdim)
 256    gstID2 = gst_setup(ni_l,nj_l,ntrunc,nlev_T_even)
 257    if(mmpi_myid == 0) write(*,*) 'BHI:returned value of gstID =',gstID
 258    if(mmpi_myid == 0) write(*,*) 'BHI:returned value of gstID2=',gstID2
 259
 260    call mmpi_setup_latbands(nj_l, latPerPE, latPerPEmax, myLatBeg, myLatEnd)
 261    call mmpi_setup_lonbands(ni_l, lonPerPE, lonPerPEmax, myLonBeg, myLonEnd)
 262
 263    call mmpi_setup_m(ntrunc,mymBeg,mymEnd,mymSkip,mymCount)
 264    call mmpi_setup_n(ntrunc,mynBeg,mynEnd,mynSkip,mynCount)
 265
 266    call gst_ilaList_mpiglobal(ilaList_mpiglobal,nla_mpilocal,maxMyNla,gstID,mymBeg,mymEnd,mymSkip,mynBeg,mynEnd,mynSkip)
 267    call gst_ilaList_mpilocal(ilaList_mpilocal,gstID,mymBeg,mymEnd,mymSkip,mynBeg,mynEnd,mynSkip)
 268
 269    ! compute mpilocal control vector size
 270    cvDim_mpilocal = 0
 271    do jm = mymBeg, mymEnd, mymSkip
 272      do jn = mynBeg, mynEnd, mynSkip
 273        if(jm.le.jn) then
 274          if(jm == 0) then
 275            ! only real component for jm=0
 276            cvDim_mpilocal = cvDim_mpilocal + 1*nkgdimSqrt
 277          else
 278            ! both real and imaginary components for jm>0
 279            cvDim_mpilocal = cvDim_mpilocal + 2*nkgdimSqrt
 280          endif
 281        endif
 282      enddo
 283    enddo
 284    cvDim_out = cvDim_mpilocal
 285
 286    ! also compute mpiglobal control vector dimension
 287    call rpn_comm_allreduce(cvDim_mpilocal,cvDim_mpiglobal,1,"mpi_integer","mpi_sum","GRID",ierr)
 288
 289    allocate(PtoT(nlev_T+1,nlev_M,nj_l))
 290    allocate(tantheta(nlev_M,nj_l))
 291    allocate(rgsig(nj_l,nkgdim))
 292    allocate(tgstdbg(ni_l,nj_l))
 293    rgsiguu => rgsig(1:nj_l,nspositVO:nspositVO+nlev_M-1)
 294    rgsigvv => rgsig(1:nj_l,nspositDI:nspositDI+nlev_M-1)
 295    rgsigtt => rgsig(1:nj_l,nspositTT:nspositTT+nlev_T-1)
 296    rgsigq  => rgsig(1:nj_l,nspositQ :nspositQ +nlev_T-1)
 297    rgsigps => rgsig(1:nj_l,nspositPS)
 298    allocate(rgsigtb(nj_l,nlev_T))
 299    allocate(rgsigpsb(nj_l))
 300    allocate(corns(nkgdim2,nkgdim2,0:ntrunc))
 301    allocate(rstddev(nkgdim2,0:ntrunc))
 302
 303    if(mmpi_myid == 0) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 304
 305    zps = 101000.D0
 306    call czp_fetch1DLevels(vco_anl, zps, &
 307                           profM_opt=pressureProfile_M, profT_opt=pressureProfile_T)
 308
 309    llfound = .false.
 310    nlev_bdl = 0
 311    do jlev = 1, nlev_M
 312      if(.not.llfound .and. (pressureProfile_M(jlev) .ge. rlimlv_bdl  )) then
 313        nlev_bdl = jlev
 314        llfound = .true.
 315      endif
 316    enddo
 317
 318    inquire(file=bFileName,exist=lExists)
 319    IF ( lexists )then
 320      ierr = fnom(nulbgst,bFileName,'RND+OLD+R/O',0)
 321      if ( ierr == 0 ) then
 322        ierr =  fstouv(nulbgst,'RND+OLD')
 323      else
 324        call utl_abort('BHI_setup:NO BACKGROUND STAT FILE!!')
 325      endif
 326    endif
 327
 328    call BHI_rdspPtoT
 329
 330    call BHI_readcorns2
 331    if(mmpi_myid == 0) write(*,*) 'Memory Used (after readcorns2): ',get_max_rss()/1024,'Mb'
 332
 333    call BHI_sutg
 334
 335    if(stddevmode == 'GD2D') then
 336      call BHI_rdstd
 337    elseif(stddevMode == 'SP2D') then
 338      call BHI_rdspstd_newfmt
 339    else
 340      call utl_abort('BHI_setup: unknown stddevMode')
 341    endif
 342
 343    call BHI_scalestd
 344
 345    call BHI_sucorns2
 346    if(mmpi_myid == 0) write(*,*) 'Memory Used (after sucorns2): ',get_max_rss()/1024,'Mb'
 347
 348    ierr = fstfrm(nulbgst)
 349    ierr = fclos(nulbgst)
 350
 351    if(mmpi_myid == 0) write(*,*) 'END OF BHI_SETUP'
 352
 353    initialized = .true.
 354
 355  END SUBROUTINE BHI_setup
 356
 357
 358  subroutine bhi_getScaleFactor(scaleFactor_out)
 359    implicit none
 360
 361    ! Arguments:
 362    real(8), intent(out) :: scaleFactor_out(:)
 363
 364    ! Locals:
 365    integer :: jlev
 366
 367    do jlev = 1, max(nLev_M,nLev_T)
 368      scaleFactor_out(jlev) = scaleFactor(jlev)
 369    enddo
 370
 371  end subroutine bhi_getScaleFactor
 372
 373
 374  SUBROUTINE BHI_scalestd
 375    implicit none
 376
 377    ! Locals:
 378    integer :: jlev, jlon, jlat, shift_level, Vcode_anl
 379
 380    Vcode_anl = vco_anl%Vcode
 381    if(Vcode_anl == 5002) then
 382      shift_level = 1
 383    else
 384      shift_level = 0
 385    endif
 386
 387    do jlev = 1, nlev_M
 388      do jlat = 1, nj_l
 389        rgsiguu(jlat,jlev) =                                 scaleFactor(jlev+shift_level)*rgsiguu(jlat,jlev)
 390        rgsigvv(jlat,jlev) = scaleFactorCC(jlev+shift_level)*scaleFactor(jlev+shift_level)*rgsigvv(jlat,jlev)
 391      enddo
 392    enddo
 393    do jlev = 1, nlev_T
 394      do jlat = 1, nj_l
 395        rgsigtt(jlat,jlev) =                     scaleFactor(jlev)*rgsigtt(jlat,jlev)
 396        rgsigq(jlat,jlev)  = scaleFactorLQ(jlev)*scaleFactor(jlev)*rgsigq(jlat,jlev)
 397        rgsigtb(jlat,jlev) =                     scaleFactor(jlev)*rgsigtb(jlat,jlev)
 398      enddo
 399    enddo
 400    do jlat = 1, nj_l
 401      rgsigpsb(jlat) = scaleFactor(max(nLev_M,nLev_T))*rgsigpsb(jlat)
 402      rgsigps(jlat)  = scaleFactor(max(nLev_M,nLev_T))*rgsigps(jlat)
 403    enddo
 404    ! User has the option to not scale down the STDDEV of TG (because underestimated in Benkf)
 405    if(scaleTG) then
 406    do jlat = 1, nj_l
 407      do jlon = 1, ni_l
 408        tgstdbg(jlon,jlat) = scaleFactor(max(nLev_M,nLev_T))*tgstdbg(jlon,jlat)
 409      enddo
 410    enddo
 411    endif
 412
 413  END SUBROUTINE BHI_scalestd
 414
 415
 416  SUBROUTINE BHI_SUCORNS2
 417    implicit none
 418
 419    ! Locals:
 420    real(8) :: eigenval(nkgdim2), eigenvec(nkgdim2,nkgdim2), result(nkgdim2,nkgdim2)
 421    real(8) :: eigenvalsqrt(nkgdim2), eigenvec2(nkgdim2,nkgdim2), eigenvalsqrt2(nkgdim2)
 422    integer :: jlat,jn,jk1,jk2,jk3
 423    integer :: ilwork,info,klatPtoT
 424    integer :: iulcorvert, ikey, nsize
 425    real(8) :: zwork(2*4*nkgdim2)
 426    real(8) :: ztt(nlev_T,nlev_T,(ntrunc+1)),ztpsi(nlev_T,nlev_M,(ntrunc+1))
 427    real(8) :: ztlen,zcorr,zr,zpres1,zpres2
 428    real(8) :: zfact,zfact2,zcoriolis,zpsips(nLevPtoT)
 429    real(8) :: zpsi(nlev_M,nlev_M),zfacttb(nj_l,nlev_T),zfactpsb(nj_l)
 430    real(8) :: corvert(nkgdim2,nkgdim2)
 431    real(8),allocatable :: corns_temp(:,:,:)
 432    logical :: lldebug, lfound_sqrt
 433    ! standard file variables
 434    integer :: ini,inj,ink, inpas, inbits, idatyp, ideet 
 435    integer :: ip1,ip2,ip3,ig1,ig2,ig3,ig4,iswa,ilength,idltf
 436    integer :: iubc,iextr1,iextr2,iextr3,ierr
 437    integer :: idateo
 438    character(len=2)  :: cltypvar
 439    character(len=1)  :: clgrtyp
 440    character(len=4)  :: clnomvar
 441    character(len=12) :: cletiket
 442    integer :: fstprm,fstinf
 443    integer :: fnom,fstouv,fstfrm,fclos
 444
 445    lldebug = .false.
 446
 447    iulcorvert = 0
 448    if(mmpi_myid==0) then
 449      ierr = fnom(iulcorvert,'corvert_modular.fst','RND',0)
 450      ierr = fstouv(iulcorvert,'RND')
 451    endif
 452
 453    klatPtoT = 1
 454    zfactpsb(:) = 0.0d0
 455    zfacttb(:,:) = 0.0d0
 456
 457    if(lldebug) then
 458      do jk1 = 1, nlev_T
 459        do jk2 = 1, nlevPtoT
 460          write(622,*) jk1,jk2,klatPtoT,PtoT(jk1,jk2,klatPtoT)
 461        enddo
 462      enddo
 463    endif
 464
 465    ! explicitly compute the balanced temperature and temperature-psi correlations
 466
 467    do jn = 0, ntrunc
 468
 469      ztpsi(:,:,jn+1) = 0.0d0
 470      ztt(:,:,jn+1) = 0.0d0
 471      do jk1 = 1, nlevPtoT
 472        do jk2 = 1, nlev_T
 473          do jk3 = 1, nlevPtoT
 474            ztpsi(jk2,jk1,jn+1) = ztpsi(jk2,jk1,jn+1)+PtoT(jk2,jk3,klatPtoT)*corns(jk3,jk1,jn)
 475          enddo
 476        enddo
 477      enddo
 478      if(nlevPtoT.lt.nlev_M) then
 479        do jk1 = (nlevPtoT+1), nlev_M
 480          do jk2 = 1, nlev_T
 481            ztpsi(jk2,jk1,jn+1) = ztpsi(jk2,nlevPtoT,jn+1)
 482          enddo
 483        enddo
 484      endif
 485      do jk1 = 1, nlev_T
 486        do jk2 = 1, nlev_T
 487          do jk3 = 1, nlevPtoT
 488            ztt(jk2,jk1,jn+1) = ztt(jk2,jk1,jn+1)+ztpsi(jk2,jk3,jn+1)*PtoT(jk1,jk3,klatPtoT)
 489          enddo
 490        enddo
 491      enddo
 492    enddo
 493
 494    if(lldebug) then
 495      write(620,*) ztt
 496      write(621,*) ztpsi
 497    endif
 498
 499    ! fill in blocks for balance temperature
 500
 501    do jn = 0, ntrunc
 502      do jk1 = 1, nlev_T
 503        do jk2 = 1, nlev_T
 504          corns(nkgdim+jk2,nkgdim+jk1,jn) = ztt(jk2,jk1,jn+1)
 505        enddo
 506      enddo
 507      do jk1 = 1, nlev_M
 508        do jk2 = 1, nlev_T
 509          corns(       jk1,nkgdim+jk2,jn) = ztpsi(jk2,jk1,jn+1)
 510          corns(nkgdim+jk2,       jk1,jn) = ztpsi(jk2,jk1,jn+1)
 511        enddo
 512      enddo
 513    enddo
 514
 515    ! Save un-localized PSI correlations
 516    do jk2 = 1, nlev_M
 517      do jk1 = 1, nlev_M
 518        zpsi(jk1,jk2) = 0.0d0
 519        do jn = 0, ntrunc
 520          zpsi(jk1,jk2) = zpsi(jk1,jk2)+((2*jn+1)*corns(jk1,jk2,jn))
 521        enddo
 522      enddo
 523    enddo
 524
 525    ! Apply vertical localization to corrns
 526
 527    ! unbalanced temperature
 528    ztlen = rvlocunbalt
 529    if(ztlen.gt.0.0d0) then
 530      ! calculate 5'th order function (from Gaspari and Cohn)
 531      do jk1 = 1, nlev_T
 532        zpres1 = log(pressureProfile_T(jk1))
 533        do jk2 = 1, nlev_T
 534          zpres2 = log(pressureProfile_T(jk2))
 535          zr = abs(zpres2 - zpres1)
 536          zcorr = gasparicohn(ztlen,zr)
 537          do jn = 0, ntrunc
 538            corns(jk1+2*nlev_M,jk2+2*nlev_M,jn)  =   &
 539                 corns(jk1+2*nlev_M,jk2+2*nlev_M,jn)*zcorr
 540          enddo
 541        enddo
 542      enddo
 543    endif
 544
 545    ! balanced temperature
 546    ztlen = rvlocbalt
 547    if(ztlen.gt.0.0d0) then
 548      ! calculate 5'th order function (from Gaspari and Cohn)
 549      do jk1 = 1, nlev_T
 550        zpres1 = log(pressureProfile_T(jk1))
 551        do jk2 = 1, nlev_T
 552          zpres2 = log(pressureProfile_T(jk2))
 553          zr = abs(zpres2 - zpres1)
 554          zcorr = gasparicohn(ztlen,zr)
 555          do jn = 0, ntrunc
 556            corns(jk1+nkgdim,jk2+nkgdim,jn)  =        &
 557                 corns(jk1+nkgdim,jk2+nkgdim,jn)*zcorr
 558          enddo
 559        enddo
 560      enddo
 561    endif
 562
 563    ! streamfunction 
 564    ztlen = rvlocpsi    ! specify length scale (in units of ln(Pressure))
 565    if(ztlen.gt.0.0d0) then
 566      ! calculate 5'th order function (from Gaspari and Cohn)
 567      do jk1 = 1, nlev_M
 568        zpres1 = log(pressureProfile_M(jk1))
 569        do jk2 = 1, nlev_M
 570          zpres2 = log(pressureProfile_M(jk2))
 571          zr = abs(zpres2 - zpres1)
 572          zcorr = gasparicohn(ztlen,zr)
 573          do jn = 0, ntrunc
 574            corns(jk1,jk2,jn) = corns(jk1,jk2,jn)*zcorr
 575          enddo
 576        enddo
 577      enddo
 578    endif
 579
 580    ! temp-psi cross-correlations
 581    ztlen = rvlocpsitt    ! specify length scale (in units of ln(Pressure))
 582    if(ztlen.gt.0.0d0) then
 583      ! calculate 5'th order function (from Gaspari and Cohn)
 584      do jk1 = 1, nlev_M
 585        zpres1 = log(pressureProfile_M(jk1))
 586        do jk2 = 1, nlev_T
 587          zpres2 = log(pressureProfile_T(jk2))
 588          zr = abs(zpres2 - zpres1)
 589          zcorr = gasparicohn(ztlen,zr)
 590          do jn = 0, ntrunc
 591            corns(jk1,jk2+nkgdim,jn) = corns(jk1,jk2+nkgdim,jn)*zcorr
 592            corns(jk2+nkgdim,jk1,jn) = corns(jk2+nkgdim,jk1,jn)*zcorr
 593          enddo
 594        enddo
 595      enddo
 596    endif
 597
 598    ! velocity potential (unbalanced)
 599    ztlen = rvlocchi    ! specify length scale (in units of ln(Pressure))
 600    if(ztlen.gt.0.0d0) then
 601      ! calculate 5'th order function (from Gaspari and Cohn)
 602      do jk1 = 1, nlev_M
 603        zpres1 = log(pressureProfile_M(jk1))
 604        do jk2 = 1, nlev_M
 605          zpres2 = log(pressureProfile_M(jk2))
 606          zr = abs(zpres2 - zpres1)
 607          zcorr = gasparicohn(ztlen,zr)
 608          do jn = 0, ntrunc
 609            corns(jk1+nlev_M,jk2+nlev_M,jn) = corns(jk1+nlev_M,jk2+nlev_M,jn)*zcorr
 610          enddo
 611        enddo
 612      enddo
 613    endif
 614
 615    ! cross-correlation t'-ps'
 616    if(.true.) then
 617    ztlen = rvlocunbalt    ! specify length scale (in units of ln(Pressure))
 618    if(ztlen.gt.0.0d0) then
 619      ! calculate 5'th order function (from Gaspari and Cohn)
 620      zpres1 = log(pressureProfile_T(nlev_T))
 621      do jk2 = 1, nlev_T
 622        zpres2 = log(pressureProfile_T(jk2))
 623        zr = abs(zpres2 - zpres1)
 624        zcorr = gasparicohn(ztlen,zr)
 625        do jn = 0, ntrunc
 626          corns(1+2*nlev_M+2*nlev_T,jk2+2*nlev_M,jn)  =       &
 627               corns(1+2*nlev_M+2*nlev_T,jk2+2*nlev_M,jn)*zcorr
 628          corns(jk2+2*nlev_M,1+2*nlev_M+2*nlev_T,jn)  =       &
 629               corns(jk2+2*nlev_M,1+2*nlev_M+2*nlev_T,jn)*zcorr
 630        enddo
 631      enddo
 632    endif
 633    endif
 634
 635    ! humidity
 636    ztlen = rvloclq    ! specify length scale (in units of ln(Pressure))
 637    if(ztlen.gt.0.0d0) then
 638      ! calculate 5'th order function (from Gaspari and Cohn)
 639      do jk1 = 1, nlev_T
 640        zpres1 = log(pressureProfile_T(jk1))
 641        do jk2 = 1, nlev_T
 642          zpres2 = log(pressureProfile_T(jk2))
 643          zr = abs(zpres2 - zpres1)
 644          zcorr = gasparicohn(ztlen,zr)
 645          do jn = 0, ntrunc
 646            corns(jk1+2*nlev_M+nlev_T,jk2+2*nlev_M+nlev_T,jn)  =       &
 647                 corns(jk1+2*nlev_M+nlev_T,jk2+2*nlev_M+nlev_T,jn)*zcorr
 648          enddo
 649        enddo
 650      enddo
 651    endif
 652
 653    ! compute total vertical correlations (including for balanced temperature)
 654    if(.true.) then
 655      do jk2 = 1, nkgdim2
 656        do jk1 = 1, nkgdim2
 657          corvert(jk1,jk2) = 0.0d0
 658          do jn = 0, ntrunc
 659            corvert(jk1,jk2) = corvert(jk1,jk2)+((2*jn+1)*corns(jk1,jk2,jn))
 660          enddo
 661        enddo
 662      enddo
 663
 664      if(lldebug) then
 665        write(701,*) corvert
 666        write(702,*) zpsi
 667      endif
 668
 669      if(mmpi_myid == 0) then
 670        ikey = fstinf(NULBGST,ini,inj,ink,-1,'CORRNS',-1,0,-1,' ','ZZ')
 671        ierr = fstprm(ikey,idateo,ideet,inpas,ini,inj,ink, inbits        &
 672             ,idatyp,ip1,ip2,ip3,cltypvar,clnomvar,cletiket,clgrtyp      &
 673             ,ig1,ig2,ig3,ig4,iswa,ilength,idltf,iubc,iextr1,iextr2      &
 674             ,iextr3)
 675
 676        ini = nkgdim2
 677        inj = nkgdim2
 678        ink = 1
 679        ip1 = 0
 680        ip2 = ntrunc
 681        ip3 = 0
 682        clnomvar = 'ZV'
 683        cletiket = 'CORVERT'
 684        idatyp = 5
 685
 686        ierr = utl_fstecr(corvert, -inbits, iulcorvert, idateo    &
 687             , ideet,inpas, ini, inj, ink, ip1, ip2, ip3, cltypvar,     &
 688             clnomvar,cletiket,clgrtyp,ig1, ig2, ig3, ig4, idatyp,      &
 689             .true.)
 690
 691      endif
 692
 693      ! Modify RGSIGTB to obtain correct sigma_Tb
 694      do jk1 = 1, nlev_T
 695        zfact = corvert(jk1+nkgdim,jk1+nkgdim)
 696        do jlat = 1, nj_l
 697          zcoriolis = abs(2.d0*ec_Omega*gst_getrmu(jlat,gstID))
 698          if(zfact.gt.0.0d0.and.zcoriolis.ne.0.0d0) then
 699            zfact2 = 1.0d0/(zfact*zcoriolis*zcoriolis)
 700          else 
 701            zfact2 = 0.0d0
 702          endif
 703          zfacttb(jlat,jk1) = zfacttb(jlat,jk1)+zfact2
 704        enddo
 705      enddo
 706
 707      ! Modify RGSIGPSB to obtain correct sigma_PSb
 708      do jlat = 1, nj_l
 709        do jk2 = 1, nlevPtoT
 710          zpsips(jk2) = 0.0d0
 711          do jk1 = 1, nlevPtoT
 712            zpsips(jk2) = zpsips(jk2)+PtoT(nlev_T+1,jk1,klatPtoT)*zpsi(jk1,jk2)
 713          enddo
 714        enddo
 715        zfact = 0.0d0
 716        do jk1 = 1, nlevPtoT
 717          zfact = zfact+PtoT(nlev_T+1,jk1,klatPtoT)*zpsips(jk1)
 718        enddo
 719        zcoriolis = abs(2.d0*ec_Omega*gst_getrmu(jlat,gstID))
 720        if(zfact.gt.0.0d0.and.zcoriolis.ne.0.0d0) then
 721          zfact2 = 1.0d0/(zfact*zcoriolis*zcoriolis)
 722        else 
 723          zfact2 = 0.0d0
 724        endif
 725        zfactpsb(jlat) = zfactpsb(jlat)+zfact2
 726      enddo
 727    endif
 728
 729    ! Modify RGSIGTB and RGSIGPSB to obtain correct sigma_Tb and sigma_Psb
 730    do jlat = 1, nj_l
 731      if(zfactpsb(jlat).gt.0.0d0) then
 732        rgsigpsb(jlat) = rgsigpsb(jlat)*sqrt(zfactpsb(jlat))
 733      else
 734        rgsigpsb(jlat) = 0.0d0
 735      endif          
 736      do jk1 = 1, nlev_T
 737        if(zfacttb(jlat,jk1).gt.0.0d0) then
 738          rgsigtb(jlat,jk1) = rgsigtb(jlat,jk1)*sqrt(zfacttb(jlat,jk1))
 739        else
 740          rgsigtb(jlat,jk1) = 0.0d0
 741        endif
 742      enddo
 743    enddo
 744
 745    ! compute square-root of corns for each total wavenumber
 746    allocate(corns_temp(nkgdim2,nkgdim2,0:ntrunc))
 747    corns_temp(:,:,:)=0.0d0
 748    do jn = mmpi_myid, ntrunc, mmpi_nprocs
 749
 750      do jk1 = 1, nkgdim2
 751         do jk2 = 1, nkgdim2
 752            eigenvec(jk2,jk1) = corns(jk2,jk1,jn)
 753         enddo
 754      enddo
 755
 756      ! CALCULATE EIGENVALUES AND EIGENVECTORS.
 757      ilwork = 4*nkgdim2*2
 758      call dsyev('V','U',nkgdim2,eigenvec,nkgdim2,eigenval,zwork,ilwork,info)
 759      if(info.ne.0) then
 760        write(*,*) 'bhi_sucorns2: non-zero value of info =',info,' returned by dsyev for wavenumber ',jn
 761        call utl_abort('BHI_SUCORNS')
 762      endif
 763
 764      ! set selected number of eigenmodes to zero
 765      if(numModeZero.gt.0) then
 766        write(*,*) 'bhi_sucorns2: setting ',numModeZero,' eigenvalues to zero for wavenumber n=',jn
 767        write(*,*) 'bhi_sucorns2: original eigenvalues=',eigenval(:)
 768        do jk1 = 1, numModeZero
 769          eigenval(jk1) = 0.0d0
 770        enddo
 771        write(*,*) 'bhi_sucorns2: modified eigenvalues=',eigenval(:)
 772      endif
 773
 774      do jk1 = 1, nkgdim2
 775        if(eigenval(jk1).lt.1.0d-15) then
 776          eigenvalsqrt(jk1) = 0.0d0
 777        else
 778          eigenvalsqrt(jk1) = sqrt(eigenval(jk1))
 779        endif
 780      enddo
 781 
 782      ! Reverse the order of E-Values if old formulation (for compatibility)
 783      if(.not.squareSqrt) then
 784        do jk1 = 1, nkgdim2
 785          eigenvalsqrt2(jk1) = eigenvalsqrt(nkgdim2-jk1+1)
 786          do jk2 = 1, nkgdim2
 787            eigenvec2(jk2,jk1) = eigenvec(jk2,nkgdim2-jk1+1)
 788          enddo
 789        enddo
 790        eigenvalsqrt(:) = eigenvalsqrt2(:)
 791        eigenvec(:,:) = eigenvec2(:,:)
 792      endif
 793
 794      ! compute E * lambda^1/2
 795      result(:,:) = 0.0d0
 796      do jk1 = 1, nkgdimSqrt
 797         do jk2 = 1, nkgdim2
 798            result(jk2,jk1) = eigenvec(jk2,jk1)*eigenvalsqrt(jk1)
 799         enddo
 800      enddo
 801
 802      ! compute (E * lambda^1/2) * E^T if new formulation
 803      if(squareSqrt) then
 804        do jk1 = 1, nkgdim2
 805          do jk2 = 1, nkgdim2
 806            do jk3 = 1, nkgdim2
 807              corns_temp(jk2,jk1,jn) = corns_temp(jk2,jk1,jn) + result(jk2,jk3)*eigenvec(jk1,jk3)
 808            enddo
 809          enddo
 810        enddo
 811      else
 812        corns_temp(:,:,jn) = result(:,:)
 813      endif
 814
 815      !if(jn == 30) then
 816      !  write(200,*) corns(:,:,jn)
 817      !  write(201,*) corns_temp(:,:,jn)
 818      !  write(202,*) eigenval(:)
 819      !  write(203,*) eigenvec(:,:)
 820      !  call flush(200)
 821      !  call flush(201)
 822      !  call flush(202)
 823      !  call flush(203)
 824      !endif
 825
 826    enddo ! jn
 827
 828    nsize = nkgdim2*nkgdim2*(ntrunc+1)
 829    call rpn_comm_allreduce(corns_temp,corns,nsize,"mpi_double_precision","mpi_sum","GRID",ierr)
 830    deallocate(corns_temp)
 831
 832    if(mmpi_myid==0) then
 833      ierr = fstfrm(iulcorvert)
 834      ierr = fclos(iulcorvert)
 835    endif
 836
 837    if(ReadWrite_sqrt) then
 838      ! if desired, read precomputed sqrt of corns which overwrites computed matrix
 839      call readcorns_sqrt(lfound_sqrt)
 840      if(.not.lfound_sqrt) then
 841        ! if precomputed sqrt does not exist in stats, then write it out to a separate file
 842        call writecorns_sqrt
 843      endif
 844    endif
 845
 846  END SUBROUTINE BHI_SUCORNS2
 847
 848
 849  SUBROUTINE WRITECORNS_SQRT
 850    implicit none
 851
 852    ! Locals:
 853    integer :: jn, nulcorns_sqrt, ierr
 854    ! standard file variables
 855    integer :: ip1,ip2,ip3
 856    integer :: idateo, ipak, idatyp
 857    integer :: fnom, fstouv,  fstfrm, fclos
 858
 859    write(*,*) 'WRITECORNS_SQRT: CORNS_SQRT will be written to file corns_sqrt.fst for NTRUNC =', ntrunc
 860
 861    if(mmpi_myid==0) then
 862      nulcorns_sqrt = 0
 863      ierr = fnom(nulcorns_sqrt,'corns_sqrt.fst','RND',0)
 864      ierr = fstouv(nulcorns_sqrt,'RND')
 865
 866      ipak = -32
 867      idatyp = 5
 868      ip1 = 0
 869      ip3 = ntrunc
 870      idateo = 0
 871
 872      do jn = 0, ntrunc
 873        ip2 = jn
 874        ierr = utl_fstecr(corns(1,1,jn),ipak,nulcorns_sqrt,idateo,0,0,nkgdim2,nkgdim2,1,  &
 875                       ip1,ip2,ip3,'X','ZZ','CORNS_SQRT','X',0,0,0,0,idatyp,.true.)
 876      enddo
 877
 878      ierr = fstfrm(nulcorns_sqrt)  
 879      ierr = fclos(nulcorns_sqrt)
 880    endif
 881
 882  END SUBROUTINE WRITECORNS_SQRT
 883
 884
 885  SUBROUTINE READCORNS_SQRT(lfound_sqrt)
 886    implicit none
 887
 888    ! Arguments:
 889    logical, intent(out) :: lfound_sqrt
 890
 891    ! Locals:
 892    integer :: jn, icornskey
 893    integer :: jcol,jrow
 894    real(8), allocatable :: zcornssrc(:,:)
 895    ! standard file variables
 896    integer :: ini,inj,ink
 897    integer :: ip1,ip2,ip3
 898    integer :: idateo
 899    character(len=2)  :: cltypvar
 900    character(len=4)  :: clnomvar
 901    character(len=12) :: cletiket
 902
 903    allocate(zcornssrc(nkgdim2,nkgdim2))
 904
 905    write(*,*) 'READCORNS_SQRT: looking for CORNS_SQRT with NTRUNC =', ntrunc
 906    do jn = 0, ntrunc
 907
 908      ! Looking for FST record parameters..
 909      idateo = -1
 910      cletiket = 'CORNS_SQRT'
 911      ip1 = -1
 912      ip2 = jn
 913      ip3 = ntrunc
 914      cltypvar = 'X'
 915      clnomvar = 'ZZ'
 916      icornskey = utl_fstlir(ZCORNSSRC,nulbgst,INI,INJ,INK,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
 917
 918      if( jn == 0 ) then
 919        if(icornskey .lt.0 ) then
 920          write(*,*) 'READCORNS_SQRT: CORNS_SQRT not found in stats file, use computed sqrt'
 921          lfound_sqrt = .false.
 922          return
 923        else
 924          write(*,*) 'READCORNS_SQRT: CORNS_SQRT found in stats file, will use it instead of computed sqrt'
 925          lfound_sqrt = .true.
 926        endif
 927      endif
 928
 929      if (ini .ne. nkgdim2 .or. inj .ne. nkgdim2) then
 930        call utl_abort('READCORNS2: BG stat levels inconsitencies')
 931      endif
 932
 933      do jcol = 1, nkgdim2
 934        do jrow = 1, nkgdim2
 935          corns(jrow,jcol,jn) = zcornssrc(jrow,jcol)
 936        enddo
 937      enddo
 938
 939    enddo
 940
 941    deallocate(zcornssrc)
 942
 943  END SUBROUTINE READCORNS_SQRT
 944
 945
 946  FUNCTION GASPARICOHN(ztlen,zr)
 947    implicit none
 948
 949    ! Arguments:
 950    real(8), intent(in) :: ztlen
 951    real(8), intent(in) :: zr
 952    ! Result:
 953    real(8)  :: gasparicohn
 954
 955    ! Locals:
 956    real(8)  :: zlc
 957
 958    zlc = ztlen/2.0d0
 959    if(zr.le.zlc) then
 960      gasparicohn = -0.250d0*(zr/zlc)**5+0.5d0*(zr/zlc)**4             &
 961                  +0.625d0*(zr/zlc)**3-(5.0d0/3.0d0)*(zr/zlc)**2+1.0d0
 962    elseif(zr.le.(2.0d0*zlc)) then
 963      gasparicohn = (1.0d0/12.0d0)*(zr/zlc)**5-0.5d0*(zr/zlc)**4         &
 964                  +0.625d0*(zr/zlc)**3+(5.0d0/3.0d0)*(zr/zlc)**2       &
 965                  -5.0d0*(zr/zlc)+4.0d0-(2.0d0/3.0d0)*(zlc/zr)
 966    else
 967      gasparicohn = 0.0d0
 968    endif
 969    if(gasparicohn.lt.0.0d0) gasparicohn = 0.0d0
 970
 971  END FUNCTION GASPARICOHN
 972
 973
 974  SUBROUTINE BHI_CALCCORR(zgd,pcscl,klev)
 975    implicit none
 976
 977    ! Arguments:
 978    integer, intent(in)  :: klev
 979    real(8), intent(out) :: zgd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,klev)
 980    real(8), intent(in)  :: pcscl(klev)
 981
 982    ! Locals:
 983    integer :: jlev, jlat, jlon
 984    real(8) :: zr, dlfac, dltemp, dln, dlcsurn, dlc, dlcorr
 985    ! parameters that define the correlation function
 986    integer :: ntoar = 3
 987    real(8) :: dlalpha = 0.2d0
 988    integer :: kcorrtyp = 1
 989
 990    dlfac   = 1.d0/(1.d0+dlalpha)
 991    dln     = 1.d0*real(ntoar,8)
 992    dltemp  = (3.d0*(1.d0 + dlalpha))/(1.d0 + dlalpha/(dln*dln))
 993    dltemp  = dsqrt(dltemp)
 994
 995    if (kcorrtyp == 1) then
 996      ! Gaussian correlation
 997      do  jlev = 1, klev
 998        dlc = 1.d0/dble(pcscl(jlev))
 999        dlc = 0.5d0*dlc*dlc
1000        do  jlat = myLatBeg, myLatEnd
1001          zr = ec_ra * acos(gst_getRmu(jlat,gstID))
1002          dlcorr = dexp(-(zr**2)*dlc)
1003          do  jlon = myLonBeg, myLonEnd
1004            zgd(jlon,jlat,jlev) = dlcorr
1005          enddo
1006        enddo
1007      enddo
1008    elseif (kcorrtyp == 2) then
1009      ! Autoregressive (SOAR) correlation
1010      do jlev = 1, klev
1011        dlc = dltemp/dble(pcscl(jlev))
1012        dlcsurn = dlc/dln
1013        do jlat = myLatBeg, myLatEnd
1014          zr = ec_ra * acos(gst_getRmu(jlat,gstID))
1015          dlcorr = (1.d0 + dlc*zr + zr*dlc*zr*dlc/3.d0)*dexp(-zr*dlc)    &
1016            + dlalpha*(1.d0 + dlcsurn*zr + zr*dlcsurn*zr*dlcsurn/3.d0)*dexp(-zr*dlcsurn)
1017          dlcorr = dlcorr*dlfac
1018          do jlon = myLonBeg, myLonEnd
1019            zgd(jlon,jlat,jlev) = dlcorr
1020          enddo
1021        enddo
1022      enddo
1023    else
1024      call utl_abort('CALCCORR- Undefined correlation type')
1025    endif
1026
1027  END SUBROUTINE BHI_calcCorr
1028
1029
1030  SUBROUTINE BHI_SUTG
1031    implicit none
1032
1033    ! Locals:
1034    logical :: llpb
1035    integer :: ikey, jlat, jlon, jla, ezgprm, ezqkdef
1036    integer :: jn, jm, ila_mpilocal, ila_mpiglobal, inlev, itggid, inmxlev, iset, nsize
1037    integer :: ezdefset
1038    integer :: ip1style,ip1kind
1039    integer :: koutmpg
1040    real(8), allocatable :: dltg(:,:), tgstdbg_tmp(:,:)
1041    real(8) :: cortgg(nla_mpiglobal,2)
1042    real(8) :: rcscltg_vec(nlev_T_even)
1043    real(8) :: zabs, zpole, dlfac
1044    real(8) :: zsp_mpilocal(nla_mpilocal,2,nlev_T_even)
1045    real(8) :: zgd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nlev_T_even)
1046    real(8) :: zsp_mpiglobal(nla_mpiglobal,2,1)
1047    real(8),allocatable :: my_zsp_mpiglobal(:,:,:)
1048    real(4), allocatable :: TrialLandSeaMask(:,:), TrialSeaIceMask(:,:)
1049    real(4), allocatable :: AnalLandSeaMask(:,:), AnalSeaIceMask(:,:)
1050    ! standard file variables
1051    integer :: ini,inj,ink, idatyp
1052    integer :: ip1,ip2,ip3
1053    integer :: ierr,ntrials
1054    integer :: idateo
1055    integer :: fstprm,fstinf,iultg,fnom,fclos,fstouv,fstfrm
1056    integer :: ip1s(1), nulbgsts(1)
1057    integer :: TrlmNumberWanted
1058    integer :: fstlir, key, nultrl, ni_trial, nj_trial
1059    integer :: deet, npas, nbits, datyp
1060    integer :: ig1,ig2,ig3,ig4,swa, lng, dltf, ubc
1061    integer :: extra1, extra2, extra3
1062    integer :: TrialGridID
1063    character(len=2)  :: cltypvar
1064    character(len=1)  :: clgrtyp
1065    character(len=4)  :: clnomvar
1066    character(len=12) :: cletiket
1067    character(len=2) :: flnum
1068    character(len=128) :: trialfile
1069    logical :: trialExists
1070
1071    !
1072    !- 1.  Reading and processing TG standard deviations
1073    !
1074
1075    !- 1.1 Read the Std. Dev. field from ./bgcov file
1076    clnomvar = 'TG'
1077    idateo = -1
1078    inmxlev = 1
1079    ntrials = 1
1080    nulbgsts(1) = nulbgst
1081
1082    call utl_getfldprm(IP1S, IP2, IP3, INLEV, CLETIKET, CLTYPVAR, ITGGID,  &
1083                       clnomvar, idateo, inmxlev, nulbgsts, ip1style, ip1kind,  &
1084                       ntrials, koutmpg)
1085    ip1 = ip1s(1)
1086
1087    ierr = ezgprm(itggid,CLGRTYP,INI,INJ,IG1,IG2,IG3,IG4)
1088    allocate(dltg(ini,inj))
1089
1090    ikey = utl_fstlir(dltg,koutmpg,ini,inj,ink,idateo,cletiket,ip1,   &
1091           ip2, ip3, cltypvar, clnomvar)
1092
1093    !- 1.2 Rearrange the data according to the analysis grid (if necessary)
1094    if(clgrtyp == 'G' .and. ni_l == ini .and. nj_l == inj .and. ig1 == 0  &
1095          .and. ig2 ==0 .and. ig3 == 0 .and.ig4 == 0) then
1096      !- 1.2.1 The std. dev. on the analysis grid 
1097      do jlat = 1, nj_l
1098        do jlon = 1,ni_l
1099          tgstdbg(jlon,jlat) = dltg(jlon,jlat)
1100        enddo
1101      enddo
1102
1103    elseif(clgrtyp == 'G' .and. ni_l == ini .and. nj_l == inj .and. ig1 ==   &
1104            0 .and. ig2 ==1 .and. ig3 == 0 .and.ig4 == 0) then
1105       !- 1.2.2 flipped Gaussian grid no longer supported
1106       call utl_abort('bhi_sutg: The flipped Gaussian grid is no longer supported!')
1107
1108    else
1109       !- 1.2.3 The std. dev. are NOT on the analysis grid. Interpolation is needed
1110       iset = ezdefset(AnalGridID,itggid)
1111       if ( TweakTG ) then
1112          ierr = int_hInterpScalar(tgstdbg,dltg,interpDegree='NEAREST')
1113       else
1114          ierr = int_hInterpScalar(tgstdbg,dltg,interpDegree='CUBIC')
1115       end if
1116
1117    end if
1118
1119    !- 1.3 Tweaking the Std Dev.
1120
1121    !- 1.3.1 If specified at the top of the module, do not accept TG errors of more than value specified above
1122    if ( llimtg ) then
1123       if ( mmpi_myid == 0 ) write(*,*)
1124       if ( mmpi_myid == 0 ) write(*,*) 'Capping TG Std. Dev. using a max value (K) = ', rlimsuptg
1125       where ( tgstdbg > rlimsuptg) tgstdbg = rlimsuptg
1126    end if
1127
1128    !- 1.3.2 Take into account the Land-Sea mask and the Sea-Ice mask of the day
1129    if ( TweakTG ) then
1130
1131      if ( mmpi_myid == 0 ) write(*,*)
1132      if ( mmpi_myid == 0 ) write(*,*) 'Adjusting TG Std Dev based on LandSea and SeaIce masks'
1133
1134      !- Read MG and GL in the middle of the assimilation time window
1135      if ( tim_nStepObs == 1 ) then
1136         TrlmNumberWanted = 1
1137      else
1138         TrlmNumberWanted = nint( (tim_nStepObs + 1.d0) / 2.d0)
1139      end if
1140
1141      write(flnum,'(I2.2)') TrlmNumberWanted
1142      trialfile='./trlm_'//trim(flnum)
1143      inquire(file=trim(trialfile),exist=trialExists)
1144
1145      if ( .not. trialExists ) then
1146        if ( mmpi_myid == 0 ) write(*,*)
1147        if ( mmpi_myid == 0 ) write(*,*) 'Trial file not found = ', trialfile
1148        if ( mmpi_myid == 0 ) write(*,*) 'Look for an ensemble of trial files '
1149
1150        trialfile='./trlm_'//trim(flnum)//'_0001'
1151        inquire(file=trim(trialfile),exist=trialExists)
1152        if ( .not. trialExists ) then
1153           if ( mmpi_myid == 0 ) write(*,*) 'Ensemble trial file not found = ', trialfile
1154           call utl_abort('BMatrixHI : DID NOT FIND A TRIAL FIELD FILE')
1155        end if
1156      end if
1157
1158      nultrl = 0
1159      ierr = fnom(nultrl,trim(trialfile),'RND+OLD+R/O',0)
1160      ierr = fstouv(nultrl,'RND+OLD')
1161
1162      !- Determine grid size and EZSCINT ID
1163      idateo    = -1
1164      cletiket = ' '
1165      ip1      = -1
1166      ip2      = -1
1167      ip3      = -1
1168      cltypvar = ' '
1169      clnomvar = 'MG'
1170
1171      key = fstinf( nultrl,                                             & ! IN
1172                    ni_trial, nj_trial, ink,                            & ! OUT
1173                    idateo, cletiket, ip1, ip2, ip3, cltypvar, clnomvar ) ! IN
1174
1175      if (key < 0) then
1176         write(*,*)
1177         write(*,*) 'bMatrixHI: Unable to find trial field = ',clnomvar
1178         call utl_abort('BMatrixHI')
1179      end if
1180
1181      ierr = fstprm( key,                                                 & ! IN
1182                     idateo, deet, npas, ni_trial, nj_trial, ink, nbits,  & ! OUT
1183                     datyp, ip1, ip2, ip3, cltypvar, clnomvar, cletiket,  & ! OUT
1184                     clgrtyp, ig1, ig2, ig3,                              & ! OUT
1185                     ig4, swa, lng, dltf, ubc, extra1, extra2, extra3 )     ! OUT
1186
1187      allocate(TrialLandSeaMask(ni_trial, nj_trial))
1188      allocate(TrialSeaIceMask(ni_trial, nj_trial))
1189
1190      idateo   = -1
1191      cletiket = ' '
1192      ip1      = -1
1193      ip2      = -1
1194      ip3      = -1
1195      cltypvar = ' '
1196      clnomvar = 'MG'
1197      ierr = fstlir(TrialLandSeaMask, nultrl, ini, inj, ink,  &
1198                    idateo ,cletiket, ip1, ip2, ip3, cltypvar, clnomvar)
1199      if ( ierr < 0 ) then
1200         write(*,*)
1201         write(*,*) 'bMatrixHI: Unable to read trial field = ',clnomvar
1202         call utl_abort('BMatrixHI : fstlir failed')
1203      end if
1204
1205      if (ini /= ni_trial .or. inj /= nj_trial) then
1206          write(*,*)
1207          write(*,*) 'bMatrixHI: Invalid dimensions for ...'
1208          write(*,*) 'nomvar      =', trim(clnomvar)
1209          write(*,*) 'etiket      =', trim(cletiket)
1210          write(*,*) 'ip1         =', ip1
1211          write(*,*) 'Found ni,nj =', ini, inj 
1212          write(*,*) 'Should be   =', ni_trial, nj_trial
1213          call utl_abort('bMatrixHI')
1214        end if
1215
1216      clnomvar = 'GL'
1217      ierr = fstlir(TrialSeaIceMask, nultrl, ini, inj, ink,  &
1218                    idateo ,cletiket, ip1, ip2, ip3, cltypvar, clnomvar)
1219      if ( ierr < 0 ) then
1220         write(*,*)
1221         write(*,*) 'bMatrixHI: Unable to read trial field = ',clnomvar
1222         call utl_abort('BMatrixHI : fstlir failed')
1223      end if
1224
1225      if (ini /= ni_trial .or. inj /= nj_trial) then
1226          write(*,*)
1227          write(*,*) 'bMatrixHI: Invalid dimensions for ...'
1228          write(*,*) 'nomvar      =', trim(clnomvar)
1229          write(*,*) 'etiket      =', trim(cletiket)
1230          write(*,*) 'ip1         =', ip1
1231          write(*,*) 'Found ni,nj =', ini, inj 
1232          write(*,*) 'Should be   =', ni_trial, nj_trial
1233          call utl_abort('bMatrixHI')
1234      end if
1235
1236      TrialGridID  = ezqkdef( ni_trial, nj_trial, clgrtyp, ig1, ig2, ig3, ig4, nultrl )   ! IN
1237 
1238      ierr = fstfrm(nultrl)  
1239      ierr = fclos(nultrl)
1240
1241      !- Interpolate to the Analysis Grid
1242      allocate(AnalLandSeaMask(ni_l, nj_l))
1243      allocate(AnalSeaIceMask(ni_l, nj_l))
1244
1245      ierr = ezdefset(AnalGridID     , TrialGridID     ) ! IN,  IN
1246
1247      ! Nearest-neighbor interpolation
1248      ierr = int_hInterpScalar(AnalLandSeaMask, TrialLandSeaMask, interpDegree='NEAREST') ! OUT, IN
1249      ierr = int_hInterpScalar(AnalSeaIceMask , TrialSeaIceMask,  interpDegree='NEAREST') ! OUT, IN
1250
1251      deallocate(TrialLandSeaMask)
1252      deallocate(TrialSeaIceMask)
1253
1254      !- Modify the input/regridded TG Std. Dev.
1255      do jlat = 1, nj_l
1256         do jlon = 1,ni_l
1257
1258           if ( AnalLandSeaMask(jlon,jlat) > 0.1 ) then
1259             ! We take this as a land point.
1260             ! Force std. dev. to capping value
1261             tgstdbg(jlon,jlat) = rlimsuptg
1262           else if ( AnalSeaIceMask(jlon,jlat) > 0.2 ) then
1263             ! We have significant sea ice on this sea point.
1264             ! Force std. dev. to capping value
1265             tgstdbg(jlon,jlat) = rlimsuptg
1266           else
1267             ! We have an open water point. Make sure that the std. dev. is realistic
1268             ! 1.55 is slightly above the max value over the ocean in the legacy TG Std. Dev. field (in 2014)
1269             if ( tgstdbg(jlon,jlat) > 1.55d0 ) then
1270                tgstdbg(jlon,jlat) = 0.9d0
1271             end if
1272           end if
1273
1274         end do
1275      end do
1276
1277      !- Write the modified Std. Dev.
1278      if ( mmpi_myid == 0 ) then
1279        allocate(tgstdbg_tmp(ni_l,nj_l))
1280        do jlat = 1, nj_l
1281          do jlon = 1,ni_l
1282             tgstdbg_tmp(jlon,jlat) = tgstdbg(jlon,jlat)
1283          end do
1284        end do
1285
1286        iultg = 0
1287        ierr = fnom(iultg,'tg_stddev_of_the_day.fst','RND',0)
1288        ierr = fstouv(iultg,'RND')
1289
1290        ini = ni_l
1291        inj = nj_l
1292        ink = 1
1293        ip1 = 0
1294        ip2 = 0
1295        ip3 = 0
1296        idateo = 0
1297        cltypvar = 'E'
1298        clnomvar = 'TG'
1299        cletiket = 'TWEAK_STDDEV'
1300        clgrtyp = 'G'
1301        ig1 = 0
1302        ig2 = 0
1303        ig3 = 0
1304        ig4 = 0
1305        idatyp = 1
1306
1307        ierr = utl_fstecr(tgstdbg_tmp, -32, iultg, idateo,         &
1308                       0, 0, ini, inj, ink, ip1, ip2, ip3, cltypvar,         &
1309                       clnomvar,cletiket,clgrtyp,ig1, ig2, ig3, ig4, idatyp, &
1310                       .true.)
1311
1312        do jlat = 1, nj_l
1313          do jlon = 1,ni_l
1314             tgstdbg_tmp(jlon,jlat) = AnalLandSeaMask(jlon,jlat)
1315          end do
1316        end do
1317        cltypvar = 'P'
1318        clnomvar = 'MG'
1319        cletiket = 'TRIAL2ANAL'
1320        ierr = utl_fstecr(tgstdbg_tmp, -32, iultg, idateo,         &
1321                       0, 0, ini, inj, ink, ip1, ip2, ip3, cltypvar,         &
1322                       clnomvar,cletiket,clgrtyp,ig1, ig2, ig3, ig4, idatyp, &
1323                       .true.)
1324
1325        do jlat = 1, nj_l
1326          do jlon = 1,ni_l
1327             tgstdbg_tmp(jlon,jlat) = AnalSeaIceMask(jlon,jlat)
1328          end do
1329        end do       
1330        cltypvar = 'P'
1331        clnomvar = 'GL'
1332        cletiket = 'TRIAL2ANAL'
1333        ierr = utl_fstecr(tgstdbg_tmp, -32, iultg, idateo,         &
1334                       0, 0, ini, inj, ink, ip1, ip2, ip3, cltypvar,         &
1335                       clnomvar,cletiket,clgrtyp,ig1, ig2, ig3, ig4, idatyp, &
1336                       .true.)
1337
1338        ierr = fstfrm(iultg)
1339        ierr = fclos(iultg)
1340
1341        deallocate(tgstdbg_tmp)
1342      end if
1343
1344      deallocate(AnalLandSeaMask)
1345      deallocate(AnalSeaIceMask)
1346
1347    end if ! if ( TweakTG )
1348
1349    !
1350    !- 2. Compute correlations in spectral space (CORNS)
1351    !
1352    zgd(:,:,:) = 0.0d0
1353    zsp_mpilocal(:,:,:) = 0.0d0
1354    allocate(my_zsp_mpiglobal(nla_mpiglobal,2,1)) 
1355    my_zsp_mpiglobal(:,:,:) = 0.0d0
1356
1357    do jla = 1, nla_mpiglobal
1358       cortgg(jla,1) = 0.0d0
1359       cortgg(jla,2) = 0.0d0
1360    enddo
1361
1362    ! 2.4.2  Compute correlations in physical space
1363    rcscltg_vec(:) = rcscltg(1)
1364    call BHI_calccorr(zgd,rcscltg_vec,nlev_T_even)
1365
1366    ! 2.4.3  Bring back the result in spectral space
1367    call gst_setID(gstID2)
1368    call gst_reespe(zsp_mpilocal,zgd)
1369
1370    ! and make the result mpiglobal
1371    do jm = mymBeg, mymEnd, mymSkip
1372      do jn = mynBeg, mynEnd, mynSkip
1373        if(jm.le.jn) then
1374          ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
1375          ila_mpilocal  = ilaList_mpilocal(ila_mpiglobal)
1376          my_zsp_mpiglobal(ila_mpiglobal,:,1) = zsp_mpilocal(ila_mpilocal,:,1)
1377        endif
1378      enddo
1379    enddo
1380    nsize = 2*nla_mpiglobal
1381    call rpn_comm_allreduce(my_zsp_mpiglobal(:,:,1),zsp_mpiglobal(:,:,1),nsize,"mpi_double_precision","mpi_sum","GRID",ierr)
1382    deallocate(my_zsp_mpiglobal) 
1383    ! 2.4.4  Check positiveness
1384    llpb = .false.
1385    do jla = 1, ntrunc+1
1386      zabs = abs(zsp_mpiglobal(jla,1,1))
1387      llpb = llpb.or.((zsp_mpiglobal(jla,1,1).lt.0.).and.(zabs.gt.epsilon(zabs)))
1388    enddo
1389    if(llpb) then
1390      call utl_abort(' AUTOCORRELATION  NEGATIVES')
1391    endif
1392    do jla = 1, ntrunc+1
1393      zsp_mpiglobal(jla,1,1) = abs(zsp_mpiglobal(jla,1,1))
1394    enddo
1395
1396    zpole = 0.d0
1397    do  jla = 1, ntrunc+1
1398      jn = jla-1
1399      zpole = zpole + zsp_mpiglobal(jla,1,1)*sqrt((2.d0*jn+1.d0)/2.d0)
1400    enddo
1401    if(zpole.le.0.d0) then
1402      call utl_abort('POLE VALUE NEGATIVE IN SUTG')
1403    endif
1404    do jla = 1, ntrunc+1
1405      zsp_mpiglobal(jla,1,1) = zsp_mpiglobal(jla,1,1)/zpole
1406      zsp_mpiglobal(jla,2,1) = zsp_mpiglobal(jla,2,1)/zpole
1407    enddo
1408
1409    !  2.4.5  Correlation
1410    do jm = 0, ntrunc
1411      do jn = jm, ntrunc
1412        jla = gst_getNIND(jm,gstID) + jn - jm
1413        dlfac = 0.5d0/dsqrt((2*jn+1.d0)/2.d0)
1414        cortgg(jla,1) = dlfac * zsp_mpiglobal(jn+1,1,1)
1415        cortgg(jla,2) = dlfac * zsp_mpiglobal(jn+1,1,1)
1416      enddo
1417    enddo
1418
1419    ! 2.5. For zonal modes : set to zero the imaginary part and set the correct factor 1.0 for the real part
1420    do jla = 1, ntrunc + 1
1421      cortgg(jla,1) = 0.5d0*cortgg(jla,1)
1422      cortgg(jla,2) = 0.0d0
1423    enddo
1424
1425    ! 2.6. Result in corns array
1426    do jn = 0, ntrunc
1427      ila_mpiglobal = jn + 1
1428      corns(nspositTG,nspositTG,jn) = 2.d0*cortgg(ila_mpiglobal,1)
1429    enddo
1430
1431    deallocate(dltg)
1432    !write(*,*)'DONE in SUTG'
1433
1434  END SUBROUTINE BHI_sutg
1435
1436
1437  SUBROUTINE BHI_convol
1438    implicit none
1439
1440    ! Locals:
1441    real(8) dlfact2,dlc,dsummed
1442    real(8) dtlen,zr,dlfact
1443    integer jn,jlat,jk
1444    real(8) zsp(0:ntrunc,nkgdim),zgr(nj_l,nkgdim)
1445    real(8) dlwti(nj_l),zrmu(nj_l)
1446    real(8)         :: RPORVO   = 6000.D3
1447    real(8)         :: RPORDI   = 6000.D3
1448    real(8)         :: RPORTT   = 3000.D3
1449    real(8)         :: RPORQ    = 3000.D3
1450    real(8)         :: RPORPS   = 3000.D3
1451
1452    do jlat = 1, nj_l
1453       dlwti(jlat) = gst_getrwt(jlat,gstID)
1454       zrmu(jlat)  = gst_getrmu(jlat,gstID)
1455    end do
1456
1457!     1.2 CONVERT THE CORRELATIONS IN SPECTRAL SPACE INTO SPECTRAL
1458!         COEFFICIENTS OF THE CORRELATION FUNCTION AND FUNCTION TO BE
1459!         SELF-CONVOLVED
1460    do jn = 0, ntrunc
1461      dlfact = ((2.0d0*jn +1.0d0)/2.0d0)**(0.25d0)
1462      dlfact2= ((2.0d0*jn +1.0d0)/2.0d0)**(0.25d0)
1463      do jk = 1, nkgdim
1464        zsp(jn,jk) = rstddev(jk,jn)*dlfact*dlfact2
1465      enddo
1466    enddo
1467
1468    ! Transform to physical space
1469    call gst_zleginv(gstID,zgr,zsp,nkgdim)
1470
1471    ! Truncate in horizontal extent with Gaussian window
1472    do jk = 1, nkgdim
1473      if (jk.ge.nspositVO.and.jk.lt.nspositVO+nlev_M) then
1474        dtlen = rporvo
1475      elseif (jk.ge.nspositDI.and.jk.lt.nspositDI+nlev_M) then
1476        dtlen = rpordi
1477      elseif (jk.ge.nspositTT.and.jk.lt.nspositTT+nlev_T) then
1478        dtlen = rportt
1479      elseif (jk.ge.nspositQ.and.jk.lt.nspositQ+nlev_T) then
1480        dtlen = rporq
1481      elseif (jk == nspositPS) then
1482        dtlen = rporps
1483      endif
1484
1485      if(dtlen.gt.0.0d0) then
1486        dlc = 1.d0/dble(dtlen)
1487        dlc = 0.5d0*dlc*dlc
1488        do jlat = 1, nj_l
1489          zr = ec_ra * acos(zrmu(jlat))
1490          dlfact = dexp(-(zr**2)*dlc)
1491          zgr(jlat,jk) = dlfact*zgr(jlat,jk)
1492        enddo
1493      endif
1494
1495      !write(*,*) 'zeroing length (km)=',jk,dtlen/1000.0
1496    enddo
1497
1498    ! Transform back to spectral space
1499    call gst_zlegdir(gstID,zgr,zsp,nkgdim)
1500
1501    ! Convert back to correlations
1502    do jk = 1, nkgdim
1503      do jn = 0, ntrunc
1504         zsp(jn,jk) = zsp(jn,jk)*(2.0d0/(2.0d0*jn+1.0d0))**(0.25d0)
1505      enddo
1506    enddo
1507
1508    ! PUT BACK INTO RSTDDEV
1509    do jn = 0, ntrunc
1510      do jk = 1, nkgdim
1511         rstddev(jk,jn) = zsp(jn,jk)
1512      enddo
1513    enddo
1514 
1515    ! Re-normalize to ensure correlations
1516    do jk = 1, nkgdim
1517      dsummed = 0.d0
1518      do jn = 0, ntrunc
1519        dsummed = dsummed+ dble(rstddev(jk,jn)**2)*sqrt(((2.d0*jn)+1.d0)/2.d0)
1520      enddo
1521      dsummed = sqrt(dsummed)
1522      do jn = 0, ntrunc
1523        if(dsummed.gt.1.d-30) rstddev(jk,jn) = rstddev(jk,jn)/dsummed
1524      enddo
1525    enddo
1526
1527    !     CONVERT THE SPECTRAL COEFFICIENTS OF THE CORRELATION FUNCTION
1528    !     .  BACK INTO CORRELATIONS OF SPECTRAL COMPONENTS
1529    do jn = 0, ntrunc
1530      dlfact = sqrt(0.5d0)*(1.0d0/((2.0d0*jn+1)/2.0d0))**0.25d0
1531      do jk = 1, nkgdim
1532        rstddev(jk,jn) = rstddev(jk,jn)*dlfact
1533      enddo
1534    enddo
1535
1536  END SUBROUTINE BHI_convol
1537
1538
1539  SUBROUTINE BHI_setCrossCorr(kn)
1540    implicit none
1541
1542    ! Arguments:
1543    integer, intent(in) :: kn
1544
1545    ! Locals:
1546    integer :: jblock1, inbrblock, jblock2
1547    integer :: jk1, jk2, nlev_all(numvar3d), levOffset(numvar3d+1)
1548
1549    inbrblock = numvar3d
1550    nlev_all(1) = nLev_M
1551    nlev_all(2) = nLev_M
1552    nlev_all(3) = nLev_T
1553    nlev_all(4) = nLev_T
1554    levOffset(1) = 0
1555    levOffset(2) = 1*nLev_M
1556    levOffset(3) = 2*nLev_M
1557    levOffset(4) = 2*nLev_M+1*nLev_T
1558    levOffset(5) = 2*nLev_M+2*nLev_T
1559
1560    ! Set cross-variable correlations to 0 ...
1561    do jblock1 = 1, inbrblock
1562      do jblock2 = 1, inbrblock
1563        if (jblock1.ne.jblock2) then
1564          do jk2 = 1, nlev_all(jblock2)
1565            do jk1 = 1, nlev_all(jblock1)
1566              corns(jk1 + levOffset(jblock1),jk2 + levOffset(jblock2),kn) = 0.0d0
1567            enddo
1568          enddo
1569        endif
1570      enddo
1571    enddo
1572
1573    ! ... but T'ln(ps') correlations
1574    do jk2 = 1, nkgdim
1575      do jk1 = levOffset(5)+1, levOffset(5)+numvar2d
1576        if ((jk1.ne.nspositPS.or.jk2.lt.nspositTT.or.    &
1577             jk2.ge.(nspositTT+nlev_T)).and.(jk1.ne.jk2)) then
1578          corns(jk1,jk2,kn) = 0.0d0
1579        endif
1580      enddo
1581    enddo
1582
1583    do jk2 = levOffset(5)+1, levOffset(5)+numvar2d
1584      do jk1 = 1, nkgdim
1585        if ((jk2.ne.nspositPS.or.jk1.lt.nspositTT.or.   &
1586             jk1.ge.(nspositTT+nlev_T)) .and.(jk1.ne.jk2)) then
1587          corns(jk1,jk2,kn) = 0.0d0
1588        endif
1589      enddo
1590    enddo
1591
1592  END SUBROUTINE BHI_setCrossCorr
1593
1594
1595  SUBROUTINE BHI_READCORNS2
1596    implicit none
1597
1598    ! Locals:
1599    integer :: kip1
1600    integer :: jn, istdkey,icornskey
1601    integer :: iksdim,jcol,jrow
1602    real(8), allocatable, dimension(:) :: zstdsrc
1603    real(8), allocatable, dimension(:,:) :: zcornssrc
1604    ! standard file variables
1605    integer :: ini,inj,ink
1606    integer :: ip1,ip2,ip3
1607    integer :: idateo
1608    character(len=2)  :: cltypvar
1609    character(len=4)  :: clnomvar
1610    character(len=12) :: cletiket
1611
1612    iksdim = 2*nlev_M+2*nlev_T+1    ! assume 4 3d variables and 1 2d variable (TG not included)
1613    allocate(zcornssrc(iksdim,iksdim))
1614    allocate(zstdsrc(iksdim))
1615
1616    kip1 = -1
1617
1618    do jn = 0, ntrunc
1619
1620      ! Looking for FST record parameters..
1621
1622      idateo = -1
1623      cletiket = 'RSTDDEV'
1624      ip1 = kip1
1625      ip2 = jn
1626      ip3 = -1
1627      cltypvar = 'X'
1628      clnomvar = 'SS'
1629
1630      istdkey = utl_fstlir(ZSTDSRC,nulbgst,INI,INJ,INK,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1631
1632      if(istdkey .lt.0 ) then
1633        call utl_abort('READCORNS2: Problem with background stat file')
1634      endif
1635
1636      if (ini .ne. iksdim) then
1637        call utl_abort('READCORNS2: BG stat levels inconsitencies')
1638      endif
1639
1640      ! Looking for FST record parameters..
1641
1642      idateo = -1
1643      cletiket = 'CORRNS'
1644      ip1 = kip1
1645      IP2 = JN
1646      ip3 = -1
1647      cltypvar = 'X'
1648      clnomvar = 'ZZ'
1649      icornskey = utl_fstlir(ZCORNSSRC,nulbgst,INI,INJ,INK,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1650
1651      if(icornskey .lt.0 ) then
1652        call utl_abort('READCORNS2: Problem with background stat file')
1653      endif
1654
1655      if (ini .ne. iksdim .or. inj .ne. iksdim) then
1656        call utl_abort('READCORNS2: BG stat levels inconsitencies')
1657      endif
1658
1659      do jcol = 1, nkgdim2
1660        rstddev(jcol,jn) = 0.0d0
1661        do jrow = 1, nkgdim2
1662          corns(jrow,jcol,jn) = 0.0d0
1663        enddo
1664      enddo
1665
1666      do jcol = 1, iksdim
1667        do jrow = 1, iksdim
1668          corns(jrow,jcol,jn) = zcornssrc(jrow,jcol)
1669        enddo
1670      enddo
1671
1672      ! Set cross-variable correlations to zero except between T' and ln(ps')
1673      call BHI_setcrosscorr(jn)
1674
1675      do jrow = 1, iksdim
1676        rstddev(jrow,jn) = zstdsrc(jrow)
1677      enddo
1678
1679    enddo
1680
1681    ! Apply convolution to RSTDDEV correlations
1682
1683    call BHI_convol 
1684
1685    do jn = 0, ntrunc
1686
1687      ! Re-build of correlation matrix: factorization of corns with convoluted RSTDDEV
1688      do jcol = 1, nkgdim
1689        do jrow = 1, nkgdim
1690          corns(jrow,jcol,jn) = rstddev(jrow,jn) * corns(jrow,jcol,jn)* rstddev(jcol,jn)
1691        enddo
1692      enddo
1693
1694    enddo
1695
1696    deallocate(zcornssrc)
1697    deallocate(zstdsrc)
1698
1699    !write(*,*) 'Done in READCORNS2'
1700  END SUBROUTINE BHI_READCORNS2
1701
1702
1703  SUBROUTINE BHI_RDSPSTD
1704    implicit none
1705
1706    ! Locals:
1707    integer, parameter  :: inbrvar3d=5
1708    integer, parameter  :: inbrvar2d=2
1709    integer :: jvar,jn,inix,injx,inkx
1710    integer :: ikey, jlevo, jlat,firstn,lastn
1711    real(8) :: zsp(0:ntrunc,max(nlev_M,nlev_T)),zspbuf(max(nlev_M,nlev_T))
1712    real(8) :: zgr(nj_l,max(nlev_M,nlev_T))
1713    character(len=4) :: varName3d(inbrvar3d),varName2d(inbrvar2d)
1714    ! standard file variables
1715    integer :: ini,inj,ink
1716    integer :: ip1,ip2,ip3
1717    integer :: idate(100),nlev_MT
1718    character(len=2)  :: cltypvar
1719    character(len=4)  :: clnomvar
1720    character(len=12) :: cletiket
1721    integer :: fstinf
1722
1723    data varName3d/'PP  ','UC  ','UT  ','LQ  ','TB  '/
1724    data varName2d/'UP  ','PB  '/
1725
1726    rgsig(:,:) = 0.0d0
1727    rgsigtb(:,:) = 0.0d0
1728    rgsigpsb(:) = 0.0d0
1729
1730!   2. Reading the data
1731
1732    idate(1) = -1
1733    ip1      = -1
1734    ip2      = -1
1735    ip3      = -1
1736
1737    cletiket = 'SPSTDDEV'
1738    cltypvar = 'X'
1739
1740    do jvar = 1, inbrvar3d
1741      clnomvar = varName3d(jvar)
1742      if(vnl_varLevelFromVarName(clnomvar) == 'MM') then
1743        nlev_MT = nlev_M
1744      else
1745        nlev_MT = nlev_T
1746      endif
1747      firstn = -1
1748      do jn = 0, ntrunc
1749        ip2 = jn
1750        ikey = fstinf(nulbgst,inix,injx,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1751
1752        if(ikey .ge.0 ) then
1753          ikey = utl_fstlir(zspbuf(1:nlev_MT),nulbgst,ini,inj,ink,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1754        else
1755          if(firstn == -1) firstn = jn
1756          lastn = jn
1757          zspbuf(:) = 0.0d0
1758        endif
1759
1760        if (ini .ne. nlev_MT) then
1761          call utl_abort('RDSPSTD: BG stat levels inconsitencies')
1762        endif
1763
1764        do jlevo = 1, nlev_MT
1765          zsp(jn,jlevo) = zspbuf(jlevo)
1766        enddo
1767      enddo
1768      if(mmpi_myid == 0.and.firstn.ne.-1) then
1769        write(*,*) 'WARNING: CANNOT FIND SPSTD FOR ',clnomvar, &
1770                     ' AT N BETWEEN ',firstn,' AND ',lastn,', SETTING TO ZERO!!!'
1771      endif
1772
1773      call gst_zleginv(gstID,zgr(:,1:nlev_MT),zsp(:,1:nlev_MT),nlev_MT)
1774
1775      if(clnomvar == 'PP') then
1776        do jlat = 1, nj_l
1777          do jlevo = 1, nlev_M
1778            rgsiguu(jlat,jlevo) = zgr(jlat,jlevo)
1779          enddo
1780        enddo
1781      elseif(clnomvar == 'UC' .or. clnomvar == 'CC') then
1782        do jlat = 1, nj_l
1783          do jlevo = 1, nlev_M
1784            rgsigvv(jlat,jlevo) = zgr(jlat,jlevo)
1785          enddo
1786        enddo
1787      elseif(clnomvar == 'UT') then
1788        do jlat = 1, nj_l
1789          do jlevo = 1, nlev_T
1790            rgsigtt(jlat,jlevo) = zgr(jlat,jlevo)
1791          enddo
1792        enddo
1793      elseif(clnomvar == 'TB') then
1794        do jlat = 1, nj_l
1795          do jlevo = 1, nlev_T
1796            rgsigtb(jlat,jlevo) = zgr(jlat,jlevo)
1797          enddo
1798        enddo
1799      elseif(clnomvar == 'LQ') then
1800        do jlat = 1, nj_l
1801          do jlevo = 1, nlev_T
1802            rgsigq(jlat,jlevo) = zgr(jlat,jlevo)
1803          enddo
1804        enddo
1805      endif
1806
1807    enddo
1808
1809    nlev_MT = 1
1810    do jvar = 1, inbrvar2d
1811      clnomvar = varName2d(jvar)
1812      firstn = -1
1813      do jn = 0, ntrunc
1814        ip2 = jn
1815        ikey = fstinf(nulbgst,inix,injx,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1816
1817        if(ikey .ge.0 ) then
1818          ikey = utl_fstlir(zspbuf,nulbgst,ini,inj,ink,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1819        else
1820          if(firstn == -1) firstn = jn
1821          lastn = jn
1822          zspbuf(:) = 0.0d0
1823        endif
1824
1825        zsp(jn,1) = zspbuf(1)
1826
1827      enddo
1828      if(mmpi_myid == 0.and.firstn.ne.-1) then
1829        write(*,*) 'WARNING: CANNOT FIND SPSTD FOR ',clnomvar, &
1830                     ' AT N BETWEEN ',firstn,' AND ',lastn,', SETTING TO ZERO!!!'
1831
1832      endif
1833
1834      call gst_zleginv(gstID,zgr(:,1:nlev_MT),zsp(:,1:nlev_MT),nlev_MT)
1835
1836      if(clnomvar == 'UP') then
1837        do jlat = 1, nj_l
1838          rgsigps(jlat) = zgr(jlat,1)*100.0d0
1839        enddo
1840      endif
1841      if(clnomvar == 'PB') then
1842        do jlat = 1, nj_l
1843          rgsigpsb(jlat) = zgr(jlat,1)*100.0d0
1844        enddo
1845      endif
1846
1847    enddo
1848
1849  END SUBROUTINE BHI_RDSPSTD
1850
1851
1852  SUBROUTINE BHI_RDSTD
1853    implicit none
1854
1855    ! Locals:
1856    integer, parameter  :: inbrvar3d=5
1857    integer, parameter  :: inbrvar2d=2
1858    integer :: jvar,inix,injx,inkx
1859    integer :: ikey
1860    real(8) :: zgr(nj_l,max(nlev_M,nlev_T))
1861    character(len=4) :: varName3d(inbrvar3d),varName2d(inbrvar2d)
1862    ! standard file variables
1863    integer :: ini,inj,ink  
1864    integer :: ip1,ip2,ip3
1865    integer :: idate(100),nlev_MT
1866    character(len=2)  :: cltypvar
1867    character(len=4)  :: clnomvar
1868    character(len=12) :: cletiket
1869    integer :: fstinf
1870
1871    data varName3d/'PP  ','UC  ','UT  ','LQ  ','TB  '/
1872    data varName2d/'UP  ','PB  '/
1873
1874    rgsig(:,:) = 0.0d0
1875    rgsigtb(:,:) = 0.0d0
1876    rgsigpsb(:) = 0.0d0
1877
1878!   2. Reading the data
1879
1880    idate(1) = -1
1881    ip1      = -1
1882    ip2      = -1
1883    ip3      = -1
1884
1885    cletiket = 'STDDEV'
1886    cltypvar = 'E'
1887
1888    do jvar = 1, inbrvar3d
1889      clnomvar = varName3d(jvar)
1890      if(vnl_varLevelFromVarName(clnomvar) == 'MM') then
1891        nlev_MT = nlev_M
1892      else
1893        nlev_MT = nlev_T
1894      endif
1895
1896      ikey = fstinf(nulbgst,inix,injx,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1897
1898      if(ikey .ge.0 ) then
1899        ikey = utl_fstlir(zgr(:,1:nlev_MT),nulbgst,ini,inj,ink,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1900      else
1901        write(*,*) 'RDSTD: could not read varName=',clnomvar
1902        call utl_abort('RDSTD') 
1903      endif
1904
1905      if (ink .ne. nlev_MT) then
1906        write(*,*) 'ink, nlev_MT=', ink, nlev_MT
1907        call utl_abort('RDSPSTD: BG stat levels inconsitencies')
1908      endif
1909
1910      if(clnomvar == 'PP') then
1911        rgsiguu(:,:) = zgr(:,1:nlev_M)
1912      elseif(clnomvar == 'UC' .or. clnomvar == 'CC') then
1913        rgsigvv(:,:) = zgr(:,1:nlev_M)
1914      elseif(clnomvar == 'UT') then
1915        rgsigtt(:,:) = zgr(:,1:nlev_T)
1916      elseif(clnomvar == 'TB') then
1917        rgsigtb(:,:) = zgr(:,1:nlev_T)
1918      elseif(clnomvar == 'LQ') then
1919        rgsigq(:,:) = zgr(:,1:nlev_T)
1920      endif
1921
1922    enddo
1923
1924    nlev_MT = 1
1925    do jvar = 1, inbrvar2d
1926      clnomvar = varName2d(jvar)
1927
1928      ikey = fstinf(nulbgst,inix,injx,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1929
1930      if(ikey .ge.0 ) then
1931        ikey = utl_fstlir(zgr,nulbgst,ini,inj,ink,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1932      else
1933        write(*,*) 'RDSTD: could not read varName=',clnomvar
1934        call utl_abort('RDSTD') 
1935      endif
1936
1937      if(clnomvar == 'UP') then
1938        rgsigps(:) = zgr(:,1)*100.0d0
1939      endif
1940      if(clnomvar == 'PB') then
1941        rgsigpsb(:) = zgr(:,1)*100.0d0
1942      endif
1943
1944    enddo
1945
1946  END SUBROUTINE BHI_RDSTD
1947
1948
1949  SUBROUTINE BHI_RDSPSTD_NEWFMT
1950    implicit none
1951
1952    ! Locals:
1953    integer, parameter  :: inbrvar3d=5
1954    integer, parameter  :: inbrvar2d=2
1955    integer :: jvar,jn,inix,injx,inkx,ntrunc_file
1956    integer :: ikey,jlevo,jlat
1957    real(8) :: zsp(0:ntrunc,max(nlev_M,nlev_T))
1958    real(8), allocatable :: zspbuf(:)
1959    real(8) :: zgr(nj_l,max(nlev_M,nlev_T))
1960    character(len=4) :: varName3d(inbrvar3d),varName2d(inbrvar2d)
1961    ! standard file variables
1962    integer :: ini,inj,ink
1963    integer :: ip1,ip2,ip3
1964    integer :: idate(100),nlev_MT
1965    character(len=2)  :: cltypvar
1966    character(len=4)  :: clnomvar
1967    character(len=12) :: cletiket
1968    integer :: fstinf
1969
1970    data varName3d/'PP  ','UC  ','UT  ','LQ  ','TB  '/
1971    data varName2d/'UP  ','PB  '/
1972
1973    rgsig(:,:) = 0.0d0
1974    rgsigtb(:,:) = 0.0d0
1975    rgsigpsb(:) = 0.0d0
1976
1977!   2. Reading the data
1978
1979    idate(1) = -1
1980    ip2      = -1
1981    ip3      = -1
1982
1983    cletiket = 'SPSTDDEV'
1984    cltypvar = 'X'
1985
1986    ! check if file is old format
1987    ip1 = -1
1988    clnomvar = varName3d(1)
1989    ikey = fstinf(nulbgst,inix,injx,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
1990    write(*,*) 'ini,inj,ink=',inix,injx,inkx
1991    if(inix.gt.1) then
1992      write(*,*) 'BHI_RDSPSTD_NEWFMT: ini>1, SPSTDDEV is in old format, calling BHI_RDSPSTD...'
1993      call bhi_rdspstd
1994      return
1995    endif
1996
1997    !write(*,*) 'Reading 3D variables'
1998    do jvar = 1, inbrvar3d
1999      clnomvar = varName3d(jvar)
2000      if(vnl_varLevelFromVarName(clnomvar) == 'MM') then
2001        nlev_MT = nlev_M
2002      else
2003        nlev_MT = nlev_T
2004      endif
2005      !write(*,*)'Reading ',clnomvar
2006      do jlevo = 1, nlev_MT
2007        if(vnl_varLevelFromVarName(clnomvar) == 'MM') then
2008          ip1 = vco_anl%ip1_M(jlevo)
2009        else
2010          ip1 = vco_anl%ip1_T(jlevo)
2011        endif
2012        ikey = fstinf(nulbgst,inix,ntrunc_file,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2013        ntrunc_file = ntrunc_file-1
2014
2015        allocate(zspbuf(0:ntrunc_file))
2016        if(ikey .ge.0 ) then
2017          ikey = utl_fstlir(zspbuf(0:ntrunc_file),nulbgst,ini,inj,ink,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2018        else
2019          write(*,*) 'RDSPSTD_NEWFMT: ',jvar,clnomvar,nlev_MT,jlevo,ikey,ntrunc,ntrunc_file
2020          call utl_abort('RDSPSTD_NEWFMT: SPSTDDEV record not found')
2021        endif
2022
2023        zsp(:,jlevo) = 0.0d0
2024        do jn = 0, min(ntrunc,ntrunc_file)
2025          zsp(jn,jlevo) = zspbuf(jn)
2026        enddo
2027        deallocate(zspbuf)
2028
2029      enddo
2030
2031      call gst_zleginv(gstID,zgr(:,1:nlev_MT),zsp(:,1:nlev_MT),nlev_MT)
2032
2033      if(clnomvar == 'PP') then
2034        do jlat = 1, nj_l
2035          do jlevo = 1, nlev_M
2036            rgsiguu(jlat,jlevo) = zgr(jlat,jlevo)
2037          enddo
2038        enddo
2039      elseif(clnomvar == 'UC' .or. clnomvar == 'CC') then
2040        do jlat = 1, nj_l
2041          do jlevo = 1, nlev_M
2042            rgsigvv(jlat,jlevo) = zgr(jlat,jlevo)
2043          enddo
2044        enddo
2045      elseif(clnomvar == 'UT') then
2046        do jlat = 1, nj_l
2047          do jlevo = 1, nlev_T
2048            rgsigtt(jlat,jlevo) = zgr(jlat,jlevo)
2049          enddo
2050        enddo
2051      elseif(clnomvar == 'TB') then
2052        do jlat = 1, nj_l
2053          do jlevo = 1, nlev_T
2054            rgsigtb(jlat,jlevo) = zgr(jlat,jlevo)
2055          enddo
2056        enddo
2057      elseif(clnomvar == 'LQ') then
2058        do jlat = 1, nj_l
2059          do jlevo = 1, nlev_T
2060            rgsigq(jlat,jlevo) = zgr(jlat,jlevo)
2061          enddo
2062        enddo
2063      endif
2064
2065    enddo
2066
2067    nlev_MT = 1
2068    do jvar = 1, inbrvar2d
2069      clnomvar = varName2d(jvar)
2070      ip1 = -1
2071      ikey = fstinf(nulbgst,inix,ntrunc_file,inkx,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2072      ntrunc_file = ntrunc_file-1
2073
2074      allocate(zspbuf(0:ntrunc_file))
2075
2076      if(ikey .ge.0 ) then
2077        ikey = utl_fstlir(zspbuf(0:ntrunc_file),nulbgst,ini,inj,ink,idate(1),cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2078      else
2079        write(*,*) 'RDSPSTD_NEWFMT: ',jvar,clnomvar,nlev_MT,jlevo,ikey,ntrunc,ntrunc_file
2080        call utl_abort('RDSPSTD_NEWFMT: SPSTDDEV record not found')
2081      endif
2082
2083      zsp(:,1) = 0.0d0
2084      do jn = 0, min(ntrunc,ntrunc_file)
2085        zsp(jn,1) = zspbuf(jn)
2086      enddo
2087      deallocate(zspbuf)
2088
2089      call gst_zleginv(gstID,zgr(:,1:nlev_MT),zsp(:,1:nlev_MT),nlev_MT)
2090
2091      if(clnomvar == 'UP') then
2092        do jlat = 1, nj_l
2093          rgsigps(jlat) = zgr(jlat,1)*100.0d0
2094        enddo
2095      endif
2096      if(clnomvar == 'PB') then
2097        do jlat = 1, nj_l
2098          rgsigpsb(jlat) = zgr(jlat,1)*100.0d0
2099        enddo
2100      endif
2101
2102    enddo
2103
2104  END SUBROUTINE BHI_RDSPSTD_NEWFMT
2105
2106
2107  SUBROUTINE BHI_RDSPPTOT
2108    IMPLICIT NONE
2109
2110    ! Locals:
2111    integer :: jn, jk1, jk2, ikey, ilen,jlat,inix,injx,inkx
2112    real(8) :: zsptheta(0:ntrunc,nlev_M)
2113    real(8) :: zgrtheta(nj_l,nlev_M)
2114    real(8) :: zPtoTsrc(nlev_T+1,nlev_M)
2115    real(8) :: zspPtoT(0:ntrunc,nlev_T+1,nlev_M)
2116    real(8) :: zgrPtoT(nj_l,nlev_T+1,nlev_M)
2117    real(8) :: ztheta(nlev_M)    
2118    ! standard file variables
2119    integer :: ini,inj,ink
2120    integer :: ip1,ip2,ip3
2121    integer :: idateo
2122    character(len=2)  :: cltypvar
2123    character(len=4)  :: clnomvar
2124    character(len=12) :: cletiket
2125    integer :: fstinf
2126    
2127    ip1 = -1
2128    ip3 = -1
2129    idateo = -1
2130    cletiket = 'SP_THETA'
2131    cltypvar = 'X'
2132    clnomvar = 'ZZ'
2133
2134    ! read spectral coefficients for theta
2135
2136    do jn = 0, ntrunc
2137      ip2 = jn
2138      ikey = fstinf(nulbgst,inix,injx,inkx,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2139
2140      if(ikey .ge.0 ) then
2141        ikey = utl_fstlir(ztheta,nulbgst,ini,inj,ink,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2142      else
2143        if(mmpi_myid == 0) write(*,*) 'WARNING: CANNOT FIND THETA FOR ',jn,' SETTING TO ZERO!!!'
2144        ztheta(:) = 0.0d0
2145      endif
2146
2147      do jk1 = 1, nlev_M
2148        zsptheta(jn,jk1) = ztheta(jk1)
2149      enddo
2150
2151    enddo
2152
2153    ! converting theta in physical space
2154
2155    call gst_zleginv(gstID,zgrtheta,zsptheta,nlev_M)
2156
2157    do jlat = 1, nj_l
2158      do jk1 = 1, nlev_M
2159        tantheta(jk1,jlat) = tan(zgrtheta(jlat,jk1))
2160      end do
2161    end do
2162
2163    ip1 = -1
2164    ip2 = -1
2165    ip3 = -1
2166    idateo = -1
2167    cletiket = 'SP_PtoT'
2168    cltypvar = 'X'
2169    clnomvar = 'ZZ'
2170
2171    ! read of spectral coefficients for P to T operator
2172
2173    do jn = 0, ntrunc
2174      ip2 = jn
2175      ikey = fstinf(nulbgst,inix,injx,inkx,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2176
2177      if(ikey .ge.0 ) then
2178        ikey = utl_fstlir(zPtoTsrc,nulbgst,ini,inj,ink,idateo,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
2179      else
2180        if(mmpi_myid == 0) write(*,*) 'WARNING: CANNOT FIND P_to_T FOR ',jn,' SETTING TO ZERO!!!'
2181        zPtoTsrc(:,:) = 0.0d0
2182      endif
2183
2184      do jk2 = 1, nlev_M
2185        do jk1 = 1, nlev_T+1
2186          zspPtoT(jn,jk1,jk2) = zPtoTsrc(jk1,jk2)
2187        enddo
2188      enddo
2189
2190    enddo
2191
2192    ilen = nlev_M*(nlev_T+1)
2193    call gst_zleginv(gstID,zgrPtoT,zspPtoT,ilen)
2194
2195    do jlat = 1, nj_l
2196      do jk2 = 1, nlev_M
2197        do jk1 = 1, nlev_T+1
2198          PtoT(jk1,jk2,jlat) = zgrPtoT(jlat,jk1,jk2)
2199        end do
2200      end do
2201    enddo
2202
2203  END SUBROUTINE BHI_RDSPPTOT
2204
2205
2206  SUBROUTINE BHI_truncateCV(controlVector_inout,ntruncCut)
2207    implicit none
2208    !
2209    !:Purpose: Set to zero all coefficients with total wavenumber > ntruncCut
2210    !
2211
2212    ! Arguments:
2213    real(8), pointer, intent(inout) :: controlVector_inout(:)
2214    integer,          intent(in)    :: ntruncCut
2215
2216    ! Locals:
2217    integer          :: jn, jm, ila_mpiglobal, ila_mpilocal, jlev, jdim
2218
2219    if(.not. initialized) then
2220      if(mmpi_myid == 0) write(*,*) 'bhi_truncateCV: bMatrixHI not initialized'
2221      return
2222    endif
2223
2224    if(ntruncCut.gt.ntrunc) then
2225      write(*,*) ntruncCut, ntrunc
2226      call utl_abort('bhi_truncateCV: ntruncCut is greater than ntrunc!')
2227    endif
2228
2229    jdim = 0
2230    do jlev = 1, nkgdimSqrt
2231      do jm = mymBeg, mymEnd, mymSkip
2232        do jn = mynBeg, mynEnd, mynSkip
2233          if(jm.le.jn) then
2234            ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
2235            ila_mpilocal  = ilaList_mpilocal(ila_mpiglobal)
2236            if(jm == 0) then
2237              ! only real component for jm=0
2238              jdim = jdim + 1
2239              if(jn.gt.ntruncCut) controlVector_inout(jdim) = 0.0d0
2240            else
2241              ! both real and imaginary components for jm>0
2242              jdim = jdim + 1
2243              if(jn.gt.ntruncCut) controlVector_inout(jdim) = 0.0d0
2244              jdim = jdim + 1
2245              if(jn.gt.ntruncCut) controlVector_inout(jdim) = 0.0d0
2246            endif
2247          endif
2248        enddo
2249      enddo
2250    enddo
2251
2252  END SUBROUTINE BHI_truncateCV
2253
2254
2255  SUBROUTINE BHI_bSqrt(controlVector_in, statevector, stateVectorRef_opt)
2256    implicit none
2257
2258    ! Arguments:
2259    real(8),                    intent(in)    :: controlVector_in(cvDim_mpilocal)
2260    type(struct_gsv),           intent(inout) :: statevector
2261    type(struct_gsv), optional, intent(in)    :: statevectorRef_opt
2262
2263    ! Locals:
2264    real(8),allocatable :: gd_out(:,:,:)
2265    real(8)   :: hiControlVector(nla_mpilocal,2,nkgdimSqrt)
2266
2267    if(mmpi_myid == 0) write(*,*) 'bhi_bsqrt: starting'
2268    if(mmpi_myid == 0) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2269
2270    if(.not. initialized) then
2271      if(mmpi_myid == 0) write(*,*) 'bMatrixHI not initialized'
2272      return
2273    endif
2274
2275    allocate(gd_out(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim))
2276
2277    call bhi_cain(controlVector_in,hiControlVector)
2278    call bhi_spa2gd(hiControlVector,gd_out)
2279
2280    call copyToStatevector(statevector,gd_out)
2281
2282    if (gsv_varExist(statevector,'HU')) then
2283      call gvt_transform( statevector,  &                         ! INOUT
2284                          'LQtoHU_tlm', &                         ! IN
2285                          stateVectorRef_opt=stateVectorRef_opt ) ! IN
2286    end if
2287
2288    deallocate(gd_out)
2289
2290    if(mmpi_myid == 0) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2291    if(mmpi_myid == 0) write(*,*) 'bhi_bsqrt: done'
2292
2293  END SUBROUTINE BHI_bSqrt
2294
2295
2296  SUBROUTINE BHI_bSqrtAd(statevector, controlVector_out, stateVectorRef_opt)
2297    implicit none
2298
2299    ! Arguments:
2300    real(8),                    intent(inout) :: controlVector_out(cvDim_mpilocal)
2301    type(struct_gsv),           intent(inout) :: statevector
2302    type(struct_gsv), optional, intent(in)    :: statevectorRef_opt
2303
2304    ! Locals:
2305    real(8), allocatable :: gd_in(:,:,:)
2306    real(8)   :: hiControlVector(nla_mpilocal,2,nkgdimSqrt)
2307
2308    if(.not. initialized) then
2309      if(mmpi_myid == 0) write(*,*) 'bMatrixHI not initialized'
2310      return
2311    endif
2312
2313    if(mmpi_myid == 0) write(*,*) 'bhi_bsqrtad: starting'
2314    if(mmpi_myid == 0) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2315
2316    allocate(gd_in(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim))
2317    gd_in(:,:,:) = 0.d0
2318    if (gsv_varExist(statevector,'HU')) then
2319      call gvt_transform( statevector, &                          ! INOUT
2320                          'LQtoHU_ad', &                          ! IN
2321                          stateVectorRef_opt=stateVectorRef_opt ) ! IN
2322    end if
2323
2324    call copyFromStatevector(statevector,gd_in)
2325
2326    call bhi_spa2gdad(gd_in,hiControlVector)
2327
2328    call bhi_cainad(hiControlVector,controlVector_out)
2329
2330    deallocate(gd_in)
2331
2332    if(mmpi_myid == 0) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2333    if(mmpi_myid == 0) write(*,*) 'bhi_bsqrtad: done'
2334
2335  END SUBROUTINE BHI_bSqrtAd
2336
2337
2338  SUBROUTINE copyToStatevector(statevector,gd)
2339    implicit none
2340
2341    ! Arguments:
2342    type(struct_gsv), intent(inout) :: statevector
2343    real(8),          intent(in)    :: gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim)
2344
2345    ! Locals:
2346    integer :: jlon, jlev, jlev2, jlat, jvar, ilev1, ilev2
2347    real(8), pointer :: field_r8(:,:,:)
2348    real(4), pointer :: field_r4(:,:,:)
2349
2350    do jvar = 1, vnl_numvarmax 
2351      if(gsv_varExist(statevector,vnl_varNameList(jvar))) then
2352        if (gsv_getDataKind(statevector) == 8) then
2353          call gsv_getField(statevector,field_r8,vnl_varNameList(jvar))
2354        else
2355          call gsv_getField(statevector,field_r4,vnl_varNameList(jvar))
2356        end if
2357        if(vnl_varNameList(jvar) == 'UU  ') then
2358          ilev1 = nspositVO
2359        elseif(vnl_varNameList(jvar) == 'VV  ') then
2360          ilev1 = nspositDI
2361        elseif(vnl_varNameList(jvar) == 'TT  ') then
2362          ilev1 = nspositTT
2363        elseif(vnl_varNameList(jvar) == 'HU  ' .or. vnl_varNameList(jvar) == 'LQ  ') then
2364          ilev1 = nspositQ
2365        elseif(vnl_varNameList(jvar) == 'P0  ') then
2366          ilev1 = nspositPS
2367        elseif(vnl_varNameList(jvar) == 'TG  ') then
2368          ilev1 = nspositTG
2369        else
2370          ! Cycle (instead of abort) to allow for non-NWP assimilation (e.g. chemical data assimilation)
2371!          call utl_abort('bmatrixhi_mod: copyToStatevector: No covariances available for variable:' // vnl_varNameList(jvar))
2372          cycle
2373        endif
2374        ilev2 = ilev1 - 1 + gsv_getNumLev(statevector,vnl_varLevelFromVarname(vnl_varNameList(jvar)))
2375        if (gsv_getDataKind(statevector) == 8) then
2376          do jlev = ilev1, ilev2
2377            jlev2 = jlev-ilev1+1
2378            do jlat = myLatBeg, myLatEnd
2379              do jlon = myLonBeg, myLonEnd
2380                field_r8(jlon,jlat,jlev2) = gd(jlon,jlat,jlev)
2381              enddo
2382            enddo
2383          enddo
2384        else
2385          do jlev = ilev1, ilev2
2386            jlev2 = jlev-ilev1+1
2387            do jlat = myLatBeg, myLatEnd
2388              do jlon = myLonBeg, myLonEnd
2389                field_r4(jlon,jlat,jlev2) = gd(jlon,jlat,jlev)
2390              enddo
2391            enddo
2392          enddo
2393        end if
2394      endif
2395    enddo
2396
2397  END SUBROUTINE copyToStatevector
2398
2399
2400  SUBROUTINE copyFromStatevector(statevector,gd)
2401    implicit none
2402
2403    ! Arguments:
2404    type(struct_gsv), intent(inout) :: statevector
2405    real(8),          intent(out)   :: gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim)
2406
2407    ! Locals:
2408    integer :: jlon, jlev, jlev2, jlat, jvar, ilev1, ilev2
2409    real(8), pointer :: field_r8(:,:,:)
2410    real(4), pointer :: field_r4(:,:,:)
2411
2412    do jvar = 1, vnl_numvarmax 
2413      if(gsv_varExist(statevector,vnl_varNameList(jvar))) then
2414        if (gsv_getDataKind(statevector) == 8) then
2415          call gsv_getField(statevector,field_r8,vnl_varNameList(jvar))
2416        else
2417          call gsv_getField(statevector,field_r4,vnl_varNameList(jvar))
2418        end if
2419        if(vnl_varNameList(jvar) == 'UU  ') then
2420          ilev1 = nspositVO
2421        elseif(vnl_varNameList(jvar) == 'VV  ') then
2422          ilev1 = nspositDI
2423        elseif(vnl_varNameList(jvar) == 'TT  ') then
2424          ilev1 = nspositTT
2425        elseif(vnl_varNameList(jvar) == 'HU  ') then
2426          ilev1 = nspositQ
2427        elseif(vnl_varNameList(jvar) == 'P0  ') then
2428          ilev1 = nspositPS
2429        elseif(vnl_varNameList(jvar) == 'TG  ') then
2430          ilev1 = nspositTG
2431        else
2432          ! Cycle (instead of abort) to allow for non-NWP assimilation (e.g. chemical data assimilation)
2433          cycle
2434        endif
2435        ilev2 = ilev1 - 1 + gsv_getNumLev(statevector,vnl_varLevelFromVarname(vnl_varNameList(jvar)))
2436        if (gsv_getDataKind(statevector) == 8) then
2437          do jlev = ilev1, ilev2
2438            jlev2 = jlev-ilev1+1
2439            do jlat = myLatBeg, myLatEnd
2440              do jlon = myLonBeg, myLonEnd
2441                gd(jlon,jlat,jlev) = field_r8(jlon,jlat,jlev2)
2442              enddo
2443            enddo
2444          enddo
2445        else
2446          do jlev = ilev1, ilev2
2447            jlev2 = jlev-ilev1+1
2448            do jlat = myLatBeg, myLatEnd
2449              do jlon = myLonBeg, myLonEnd
2450                gd(jlon,jlat,jlev) = field_r4(jlon,jlat,jlev2)
2451              enddo
2452            enddo
2453          enddo
2454        end if
2455      endif
2456    enddo
2457
2458  END SUBROUTINE copyFromStatevector
2459
2460
2461  SUBROUTINE BHI_reduceToMPILocal(cv_mpilocal,cv_mpiglobal)
2462    implicit none
2463
2464    ! Arguments:
2465    real(8), intent(out) :: cv_mpilocal(cvDim_mpilocal)
2466    real(8), intent(in)  :: cv_mpiglobal(:)
2467
2468    ! Locals:
2469    real(8), allocatable :: cv_allMaxMpilocal(:,:)
2470    integer, allocatable :: cvDim_allMpilocal(:), displs(:)
2471    integer, allocatable :: allnBeg(:),allnEnd(:),allnSkip(:)
2472    integer, allocatable :: allmBeg(:),allmEnd(:),allmSkip(:)
2473    integer :: jproc,cvDim_maxmpilocal,ierr
2474    integer :: jlev,jn,jm,ila_mpiglobal,jdim_mpilocal,jdim_mpiglobal
2475
2476    call rpn_comm_allreduce(cvDim_mpilocal, cvDim_maxmpilocal, &
2477                            1,"MPI_INTEGER","MPI_MAX","GRID",ierr)
2478
2479    if(mmpi_myid == 0) then
2480       allocate(cvDim_allMpiLocal(mmpi_nprocs))
2481    else
2482       allocate(cvDim_allMpiLocal(1))
2483    end if
2484
2485    call rpn_comm_gather(cvDim_mpiLocal   ,1,"mpi_integer",       &
2486                         cvDim_allMpiLocal,1,"mpi_integer",0,"GRID",ierr)
2487
2488    if(mmpi_myid == 0) then
2489       allocate(allnBeg(mmpi_nprocs))
2490       allocate(allnEnd(mmpi_nprocs))
2491       allocate(allnSkip(mmpi_nprocs))
2492       allocate(allmBeg(mmpi_nprocs))
2493       allocate(allmEnd(mmpi_nprocs))
2494       allocate(allmSkip(mmpi_nprocs))
2495    else
2496       allocate(allnBeg(1))
2497       allocate(allnEnd(1))
2498       allocate(allnSkip(1))
2499       allocate(allmBeg(1))
2500       allocate(allmEnd(1))
2501       allocate(allmSkip(1))
2502    end if
2503
2504    call rpn_comm_gather(mynBeg  ,1,"mpi_integer",       &
2505                         allnBeg ,1,"mpi_integer",0,"GRID",ierr)
2506    call rpn_comm_gather(mynEnd  ,1,"mpi_integer",       &
2507                         allnEnd ,1,"mpi_integer",0,"GRID",ierr)
2508    call rpn_comm_gather(mynSkip ,1,"mpi_integer",       &
2509                         allnSkip,1,"mpi_integer",0,"GRID",ierr)
2510
2511    call rpn_comm_gather(mymBeg  ,1,"mpi_integer",       &
2512                         allmBeg ,1,"mpi_integer",0,"GRID",ierr)
2513    call rpn_comm_gather(mymEnd  ,1,"mpi_integer",       &
2514                         allmEnd ,1,"mpi_integer",0,"GRID",ierr)
2515    call rpn_comm_gather(mymSkip ,1,"mpi_integer",       &
2516                         allmSkip,1,"mpi_integer",0,"GRID",ierr)
2517
2518    ! Prepare to data to be distributed
2519    if (mmpi_myid == 0) then
2520
2521       allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
2522
2523       !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,jlev,jm,jn,ila_mpiglobal,jdim_mpiglobal)
2524       do jproc = 0, (mmpi_nprocs-1)
2525          cv_allmaxmpilocal(:,jproc+1) = 0.d0
2526          jdim_mpilocal = 0
2527
2528          do jlev = 1, nkgdimSqrt
2529             do jm = allmBeg(jproc+1), allmEnd(jproc+1), allmSkip(jproc+1)
2530                do jn = allnBeg(jproc+1), allnEnd(jproc+1), allnSkip(jproc+1)
2531
2532                   if(jm.le.jn) then
2533                      
2534                      ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
2535                      
2536                      ! figure out index into global control vector
2537                      if(jm == 0) then
2538                         ! for jm=0 only real part
2539                         jdim_mpiglobal = ila_mpiglobal
2540                      else
2541                         ! for jm>0 both real and imaginary part
2542                         jdim_mpiglobal = 2*ila_mpiglobal-1 - (ntrunc+1)
2543                      endif
2544                      ! add offset for level
2545                      jdim_mpiglobal = jdim_mpiglobal + (jlev-1) * (ntrunc+1)*(ntrunc+1)
2546                      
2547                      ! index into local control vector computer as in cain
2548                      if(jm == 0) then
2549                         ! only real component for jm=0
2550                         jdim_mpilocal = jdim_mpilocal + 1
2551                         cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal)
2552                      else
2553                         ! both real and imaginary components for jm>0
2554                         jdim_mpilocal = jdim_mpilocal + 1
2555                         cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal)
2556                         jdim_mpilocal = jdim_mpilocal + 1
2557                         cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal+1)
2558                      endif
2559                      
2560                      if (jdim_mpilocal > cvDim_allMpiLocal(jproc+1)) then
2561                         write(*,*)
2562                         write(*,*) 'ERROR: jdim_mpilocal > cvDim_allMpiLocal(jproc+1)', jdim_mpilocal, cvDim_mpilocal
2563                         write(*,*) '       proc, jlev, jn, jm = ',jproc, jlev, jn, jm
2564                         call utl_abort('bhi_reduceToMPILocal')
2565                      end if
2566                      if (jdim_mpiglobal > cvDim_mpiglobal) then
2567                         write(*,*)
2568                         write(*,*) 'ERROR: jdim_mpiglobal > cvDim_mpiglobal', jdim_mpiglobal, cvDim_mpiglobal
2569                         write(*,*) '       proc, jlev, jn, jm = ',jproc, jlev, jn, jm
2570                         call utl_abort('bhi_reduceToMPILocal')
2571                      end if
2572
2573                   endif
2574                enddo
2575             enddo
2576          enddo
2577 
2578       end do ! jproc
2579       !$OMP END PARALLEL DO
2580
2581    else
2582       allocate(cv_allmaxmpilocal(1,1))
2583    end if
2584
2585    !- Distribute
2586    allocate(displs(mmpi_nprocs))
2587    do jproc = 0, (mmpi_nprocs-1)
2588       displs(jproc+1) = jproc*cvDim_maxMpiLocal ! displacement wrt cv_allMaxMpiLocal from which
2589                                                 ! to take the outgoing data to process jproc
2590    end do
2591
2592    call rpn_comm_scatterv(cv_allMaxMpiLocal, cvDim_allMpiLocal, displs, "mpi_double_precision", &
2593                           cv_mpiLocal, cvDim_mpiLocal, "mpi_double_precision", &
2594                           0, "GRID", ierr)
2595
2596    !- End
2597    deallocate(displs)
2598    deallocate(cv_allMaxMpiLocal)
2599    deallocate(cvDim_allMpiLocal)
2600    deallocate(allnBeg)
2601    deallocate(allnEnd)
2602    deallocate(allnSkip)
2603    deallocate(allmBeg)
2604    deallocate(allmEnd)
2605    deallocate(allmSkip)
2606
2607  END SUBROUTINE BHI_reduceToMPILocal
2608
2609
2610  SUBROUTINE BHI_reduceToMPILocal_r4(cv_mpilocal,cv_mpiglobal)
2611    implicit none
2612
2613    ! Arguments:
2614    real(4), intent(out) :: cv_mpilocal(cvDim_mpilocal)
2615    real(4), intent(in)  :: cv_mpiglobal(:)
2616
2617    ! Locals:
2618    real(4), allocatable :: cv_allMaxMpilocal(:,:)
2619    integer, allocatable :: cvDim_allMpilocal(:), displs(:)
2620    integer, allocatable :: allnBeg(:),allnEnd(:),allnSkip(:)
2621    integer, allocatable :: allmBeg(:),allmEnd(:),allmSkip(:)
2622    integer :: jproc,cvDim_maxmpilocal,ierr
2623    integer :: jlev,jn,jm,ila_mpiglobal,jdim_mpilocal,jdim_mpiglobal
2624
2625    call rpn_comm_allreduce(cvDim_mpilocal, cvDim_maxmpilocal, &
2626                            1,"MPI_INTEGER","MPI_MAX","GRID",ierr)
2627
2628    if(mmpi_myid == 0) then
2629       allocate(cvDim_allMpiLocal(mmpi_nprocs))
2630    else
2631       allocate(cvDim_allMpiLocal(1))
2632    end if
2633
2634    call rpn_comm_gather(cvDim_mpiLocal   ,1,"mpi_integer",       &
2635                         cvDim_allMpiLocal,1,"mpi_integer",0,"GRID",ierr)
2636
2637    if(mmpi_myid == 0) then
2638       allocate(allnBeg(mmpi_nprocs))
2639       allocate(allnEnd(mmpi_nprocs))
2640       allocate(allnSkip(mmpi_nprocs))
2641       allocate(allmBeg(mmpi_nprocs))
2642       allocate(allmEnd(mmpi_nprocs))
2643       allocate(allmSkip(mmpi_nprocs))
2644    else
2645       allocate(allnBeg(1))
2646       allocate(allnEnd(1))
2647       allocate(allnSkip(1))
2648       allocate(allmBeg(1))
2649       allocate(allmEnd(1))
2650       allocate(allmSkip(1))
2651    end if
2652
2653    call rpn_comm_gather(mynBeg  ,1,"mpi_integer",       &
2654                         allnBeg ,1,"mpi_integer",0,"GRID",ierr)
2655    call rpn_comm_gather(mynEnd  ,1,"mpi_integer",       &
2656                         allnEnd ,1,"mpi_integer",0,"GRID",ierr)
2657    call rpn_comm_gather(mynSkip ,1,"mpi_integer",       &
2658                         allnSkip,1,"mpi_integer",0,"GRID",ierr)
2659
2660    call rpn_comm_gather(mymBeg  ,1,"mpi_integer",       &
2661                         allmBeg ,1,"mpi_integer",0,"GRID",ierr)
2662    call rpn_comm_gather(mymEnd  ,1,"mpi_integer",       &
2663                         allmEnd ,1,"mpi_integer",0,"GRID",ierr)
2664    call rpn_comm_gather(mymSkip ,1,"mpi_integer",       &
2665                         allmSkip,1,"mpi_integer",0,"GRID",ierr)
2666
2667    ! Prepare to data to be distributed
2668    if (mmpi_myid == 0) then
2669
2670       allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
2671
2672       !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,jlev,jm,jn,ila_mpiglobal,jdim_mpiglobal)
2673       do jproc = 0, (mmpi_nprocs-1)
2674          cv_allmaxmpilocal(:,jproc+1) = 0.d0
2675          jdim_mpilocal = 0
2676
2677          do jlev = 1, nkgdimSqrt
2678             do jm = allmBeg(jproc+1), allmEnd(jproc+1), allmSkip(jproc+1)
2679                do jn = allnBeg(jproc+1), allnEnd(jproc+1), allnSkip(jproc+1)
2680
2681                   if(jm.le.jn) then
2682                      
2683                      ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
2684                      
2685                      ! figure out index into global control vector
2686                      if(jm == 0) then
2687                         ! for jm=0 only real part
2688                         jdim_mpiglobal = ila_mpiglobal
2689                      else
2690                         ! for jm>0 both real and imaginary part
2691                         jdim_mpiglobal = 2*ila_mpiglobal-1 - (ntrunc+1)
2692                      endif
2693                      ! add offset for level
2694                      jdim_mpiglobal = jdim_mpiglobal + (jlev-1) * (ntrunc+1)*(ntrunc+1)
2695                      
2696                      ! index into local control vector computer as in cain
2697                      if(jm == 0) then
2698                         ! only real component for jm=0
2699                         jdim_mpilocal = jdim_mpilocal + 1
2700                         cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal)
2701                      else
2702                         ! both real and imaginary components for jm>0
2703                         jdim_mpilocal = jdim_mpilocal + 1
2704                         cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal)
2705                         jdim_mpilocal = jdim_mpilocal + 1
2706                         cv_allmaxmpilocal(jdim_mpilocal,jproc+1) = cv_mpiglobal(jdim_mpiglobal+1)
2707                      endif
2708                      
2709                      if (jdim_mpilocal > cvDim_allMpiLocal(jproc+1)) then
2710                         write(*,*)
2711                         write(*,*) 'ERROR: jdim_mpilocal > cvDim_allMpiLocal(jproc+1)', jdim_mpilocal, cvDim_mpilocal
2712                         write(*,*) '       proc, jlev, jn, jm = ',jproc, jlev, jn, jm
2713                         call utl_abort('bhi_reduceToMPILocal')
2714                      end if
2715                      if (jdim_mpiglobal > cvDim_mpiglobal) then
2716                         write(*,*)
2717                         write(*,*) 'ERROR: jdim_mpiglobal > cvDim_mpiglobal', jdim_mpiglobal, cvDim_mpiglobal
2718                         write(*,*) '       proc, jlev, jn, jm = ',jproc, jlev, jn, jm
2719                         call utl_abort('bhi_reduceToMPILocal')
2720                      end if
2721
2722                   endif
2723                enddo
2724             enddo
2725          enddo
2726 
2727       end do ! jproc
2728       !$OMP END PARALLEL DO
2729
2730    else
2731       allocate(cv_allmaxmpilocal(1,1))
2732    end if
2733
2734    !- Distribute
2735    allocate(displs(mmpi_nprocs))
2736    do jproc = 0, (mmpi_nprocs-1)
2737       displs(jproc+1) = jproc*cvDim_maxMpiLocal ! displacement wrt cv_allMaxMpiLocal from which
2738                                                 ! to take the outgoing data to process jproc
2739    end do
2740
2741    call rpn_comm_scatterv(cv_allMaxMpiLocal, cvDim_allMpiLocal, displs, "mpi_real4", &
2742                           cv_mpiLocal, cvDim_mpiLocal, "mpi_real4", &
2743                           0, "GRID", ierr)
2744
2745    !- End
2746    deallocate(displs)
2747    deallocate(cv_allMaxMpiLocal)
2748    deallocate(cvDim_allMpiLocal)
2749    deallocate(allnBeg)
2750    deallocate(allnEnd)
2751    deallocate(allnSkip)
2752    deallocate(allmBeg)
2753    deallocate(allmEnd)
2754    deallocate(allmSkip)
2755
2756  END SUBROUTINE BHI_reduceToMPILocal_r4
2757
2758
2759  SUBROUTINE BHI_expandToMPIGlobal(cv_mpilocal,cv_mpiglobal)
2760    implicit none
2761
2762    ! Arguments:
2763    real(8), intent(in)  :: cv_mpilocal(cvDim_mpilocal)
2764    real(8), intent(out) :: cv_mpiglobal(:)
2765
2766    ! Locals:
2767    real(8), allocatable :: cv_maxmpilocal(:)
2768    real(8), pointer :: cv_allmaxmpilocal(:,:) => null()
2769    integer, allocatable :: allnBeg(:),allnEnd(:),allnSkip(:)
2770    integer, allocatable :: allmBeg(:),allmEnd(:),allmSkip(:)
2771    integer :: jlev, jn, jm, jproc, ila_mpiglobal, jdim_mpilocal, jdim_mpiglobal, ierr, cvDim_maxmpilocal
2772
2773    !
2774    !- 1.  Gather all local control vectors onto mpi task 0
2775    !
2776    call rpn_comm_allreduce(cvDim_mpilocal,cvDim_maxmpilocal,1,"mpi_integer","mpi_max","GRID",ierr)
2777
2778    allocate(cv_maxmpilocal(cvDim_maxmpilocal))
2779
2780    nullify(cv_allmaxmpilocal)
2781    if(mmpi_myid == 0) then
2782       allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
2783    else
2784       allocate(cv_allmaxmpilocal(1,1))
2785    end if
2786
2787    cv_maxmpilocal(:) = 0.0d0
2788    cv_maxmpilocal(1:cvDim_mpilocal) = cv_mpilocal(1:cvDim_mpilocal)
2789
2790    call rpn_comm_gather(cv_maxmpilocal,    cvDim_maxmpilocal, "mpi_double_precision",  &
2791                         cv_allmaxmpilocal, cvDim_maxmpilocal, "mpi_double_precision", 0, "GRID", ierr )
2792
2793    deallocate(cv_maxmpilocal)
2794
2795    !
2796    !- 2.  Reorganize gathered mpilocal control vectors into the mpiglobal control vector
2797    !
2798    if(mmpi_myid == 0) then
2799       allocate(allnBeg(mmpi_nprocs))
2800       allocate(allnEnd(mmpi_nprocs))
2801       allocate(allnSkip(mmpi_nprocs))
2802       allocate(allmBeg(mmpi_nprocs))
2803       allocate(allmEnd(mmpi_nprocs))
2804       allocate(allmSkip(mmpi_nprocs))
2805    else
2806       allocate(allnBeg(1))
2807       allocate(allnEnd(1))
2808       allocate(allnSkip(1))
2809       allocate(allmBeg(1))
2810       allocate(allmEnd(1))
2811       allocate(allmSkip(1))
2812    end if
2813
2814    call rpn_comm_gather(mynBeg  ,1,"mpi_integer",       &
2815                         allnBeg ,1,"mpi_integer",0,"GRID",ierr)
2816    call rpn_comm_gather(mynEnd  ,1,"mpi_integer",       &
2817                         allnEnd ,1,"mpi_integer",0,"GRID",ierr)
2818    call rpn_comm_gather(mynSkip ,1,"mpi_integer",       &
2819                         allnSkip,1,"mpi_integer",0,"GRID",ierr)
2820
2821    call rpn_comm_gather(mymBeg  ,1,"mpi_integer",       &
2822                         allmBeg ,1,"mpi_integer",0,"GRID",ierr)
2823    call rpn_comm_gather(mymEnd  ,1,"mpi_integer",       &
2824                         allmEnd ,1,"mpi_integer",0,"GRID",ierr)
2825    call rpn_comm_gather(mymSkip ,1,"mpi_integer",       &
2826                         allmSkip,1,"mpi_integer",0,"GRID",ierr)
2827
2828    if(mmpi_myid == 0) then
2829      cv_mpiglobal(:) = 0.0d0
2830
2831      !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,jlev,jm,jn,ila_mpiglobal,jdim_mpiglobal)
2832      do jproc = 0, (mmpi_nprocs-1)
2833        jdim_mpilocal = 0
2834
2835        do jlev = 1, nkgdimSqrt
2836          do jm = allmBeg(jproc+1), allmEnd(jproc+1), allmSkip(jproc+1)
2837            do jn = allnBeg(jproc+1), allnEnd(jproc+1), allnSkip(jproc+1)
2838              if(jm.le.jn) then
2839
2840                ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
2841
2842                ! figure out index into global control vector
2843                if(jm == 0) then
2844                  ! for jm=0 only real part
2845                  jdim_mpiglobal = ila_mpiglobal
2846                else
2847                  ! for jm>0 both real and imaginary part
2848                  jdim_mpiglobal = 2*ila_mpiglobal-1 - (ntrunc+1)
2849                endif
2850                ! add offset for level
2851                jdim_mpiglobal = jdim_mpiglobal + (jlev-1) * (ntrunc+1)*(ntrunc+1)
2852
2853                ! index into local control vector
2854                if(jm == 0) then
2855                  ! only real component for jm=0
2856                  jdim_mpilocal = jdim_mpilocal + 1
2857                  cv_mpiglobal(jdim_mpiglobal) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
2858                else
2859                  ! both real and imaginary components for jm>0
2860                  jdim_mpilocal = jdim_mpilocal + 1
2861                  cv_mpiglobal(jdim_mpiglobal) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
2862                  jdim_mpilocal = jdim_mpilocal + 1
2863                  cv_mpiglobal(jdim_mpiglobal+1) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
2864                endif
2865
2866                if(jdim_mpiglobal.gt.cvDim_mpiglobal)   &
2867                  write(*,*) 'ERROR: jdim,cvDim,mpiglobal=',jdim_mpiglobal,cvDim_mpiglobal,jlev,jn,jm
2868
2869              endif
2870            enddo
2871          enddo
2872        enddo
2873      enddo ! jproc
2874      !$OMP END PARALLEL DO
2875
2876    endif ! myid == 0 
2877
2878    deallocate(allnBeg)
2879    deallocate(allnEnd)
2880    deallocate(allnSkip)
2881    deallocate(allmBeg)
2882    deallocate(allmEnd)
2883    deallocate(allmSkip)
2884    deallocate(cv_allmaxmpilocal)
2885
2886  end SUBROUTINE BHI_expandToMPIGlobal
2887
2888
2889  SUBROUTINE BHI_expandToMPIGlobal_r4(cv_mpilocal,cv_mpiglobal)
2890    implicit none
2891
2892    ! Arguments:
2893    real(4), intent(in)  :: cv_mpilocal(cvDim_mpilocal)
2894    real(4), intent(out) :: cv_mpiglobal(:)
2895
2896    ! Locals:
2897    real(4), allocatable :: cv_maxmpilocal(:)
2898    real(4), pointer :: cv_allmaxmpilocal(:,:) => null()
2899    integer, allocatable :: allnBeg(:),allnEnd(:),allnSkip(:)
2900    integer, allocatable :: allmBeg(:),allmEnd(:),allmSkip(:)
2901    integer :: jlev, jn, jm, jproc, ila_mpiglobal, jdim_mpilocal, jdim_mpiglobal, ierr, cvDim_maxmpilocal
2902
2903    !
2904    !- 1.  Gather all local control vectors onto mpi task 0
2905    !
2906    call rpn_comm_allreduce(cvDim_mpilocal,cvDim_maxmpilocal,1,"mpi_integer","mpi_max","GRID",ierr)
2907
2908    allocate(cv_maxmpilocal(cvDim_maxmpilocal))
2909
2910    nullify(cv_allmaxmpilocal)
2911    if(mmpi_myid == 0) then
2912       allocate(cv_allmaxmpilocal(cvDim_maxmpilocal,mmpi_nprocs))
2913    else
2914       allocate(cv_allmaxmpilocal(1,1))
2915    end if
2916
2917    cv_maxmpilocal(:) = 0.0d0
2918    cv_maxmpilocal(1:cvDim_mpilocal) = cv_mpilocal(1:cvDim_mpilocal)
2919
2920    call rpn_comm_gather(cv_maxmpilocal,    cvDim_maxmpilocal, "mpi_real4",  &
2921                         cv_allmaxmpilocal, cvDim_maxmpilocal, "mpi_real4", 0, "GRID", ierr )
2922
2923    deallocate(cv_maxmpilocal)
2924
2925    !
2926    !- 2.  Reorganize gathered mpilocal control vectors into the mpiglobal control vector
2927    !
2928    if(mmpi_myid == 0) then
2929       allocate(allnBeg(mmpi_nprocs))
2930       allocate(allnEnd(mmpi_nprocs))
2931       allocate(allnSkip(mmpi_nprocs))
2932       allocate(allmBeg(mmpi_nprocs))
2933       allocate(allmEnd(mmpi_nprocs))
2934       allocate(allmSkip(mmpi_nprocs))
2935    else
2936       allocate(allnBeg(1))
2937       allocate(allnEnd(1))
2938       allocate(allnSkip(1))
2939       allocate(allmBeg(1))
2940       allocate(allmEnd(1))
2941       allocate(allmSkip(1))
2942    end if
2943
2944    call rpn_comm_gather(mynBeg  ,1,"mpi_integer",       &
2945                         allnBeg ,1,"mpi_integer",0,"GRID",ierr)
2946    call rpn_comm_gather(mynEnd  ,1,"mpi_integer",       &
2947                         allnEnd ,1,"mpi_integer",0,"GRID",ierr)
2948    call rpn_comm_gather(mynSkip ,1,"mpi_integer",       &
2949                         allnSkip,1,"mpi_integer",0,"GRID",ierr)
2950
2951    call rpn_comm_gather(mymBeg  ,1,"mpi_integer",       &
2952                         allmBeg ,1,"mpi_integer",0,"GRID",ierr)
2953    call rpn_comm_gather(mymEnd  ,1,"mpi_integer",       &
2954                         allmEnd ,1,"mpi_integer",0,"GRID",ierr)
2955    call rpn_comm_gather(mymSkip ,1,"mpi_integer",       &
2956                         allmSkip,1,"mpi_integer",0,"GRID",ierr)
2957
2958    if(mmpi_myid == 0) then
2959      cv_mpiglobal(:) = 0.0d0
2960
2961      !$OMP PARALLEL DO PRIVATE(jproc,jdim_mpilocal,jlev,jm,jn,ila_mpiglobal,jdim_mpiglobal)
2962      do jproc = 0, (mmpi_nprocs-1)
2963        jdim_mpilocal = 0
2964
2965        do jlev = 1, nkgdimSqrt
2966          do jm = allmBeg(jproc+1), allmEnd(jproc+1), allmSkip(jproc+1)
2967            do jn = allnBeg(jproc+1), allnEnd(jproc+1), allnSkip(jproc+1)
2968              if(jm.le.jn) then
2969
2970                ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
2971
2972                ! figure out index into global control vector
2973                if(jm == 0) then
2974                  ! for jm=0 only real part
2975                  jdim_mpiglobal = ila_mpiglobal
2976                else
2977                  ! for jm>0 both real and imaginary part
2978                  jdim_mpiglobal = 2*ila_mpiglobal-1 - (ntrunc+1)
2979                endif
2980                ! add offset for level
2981                jdim_mpiglobal = jdim_mpiglobal + (jlev-1) * (ntrunc+1)*(ntrunc+1)
2982
2983                ! index into local control vector
2984                if(jm == 0) then
2985                  ! only real component for jm=0
2986                  jdim_mpilocal = jdim_mpilocal + 1
2987                  cv_mpiglobal(jdim_mpiglobal) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
2988                else
2989                  ! both real and imaginary components for jm>0
2990                  jdim_mpilocal = jdim_mpilocal + 1
2991                  cv_mpiglobal(jdim_mpiglobal) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
2992                  jdim_mpilocal = jdim_mpilocal + 1
2993                  cv_mpiglobal(jdim_mpiglobal+1) = cv_allmaxmpilocal(jdim_mpilocal,jproc+1)
2994                endif
2995
2996                if(jdim_mpiglobal.gt.cvDim_mpiglobal)   &
2997                  write(*,*) 'ERROR: jdim,cvDim,mpiglobal=',jdim_mpiglobal,cvDim_mpiglobal,jlev,jn,jm
2998
2999              endif
3000            enddo
3001          enddo
3002        enddo
3003      enddo ! jproc
3004      !$OMP END PARALLEL DO
3005
3006    endif ! myid == 0 
3007
3008    deallocate(allnBeg)
3009    deallocate(allnEnd)
3010    deallocate(allnSkip)
3011    deallocate(allmBeg)
3012    deallocate(allmEnd)
3013    deallocate(allmSkip)
3014    deallocate(cv_allmaxmpilocal)
3015
3016  end SUBROUTINE BHI_expandToMPIGlobal_r4
3017
3018
3019  SUBROUTINE BHI_cain(controlVector_in,hiControlVector_out)
3020    implicit none
3021
3022    ! Arguments:
3023    real(8), intent(in)  :: controlVector_in(cvDim_mpilocal)
3024    real(8), intent(out) :: hiControlVector_out(nla_mpilocal,2,nkgdimSqrt)
3025
3026    ! Locals:
3027    integer :: jdim, jlev, jm, jn, ila_mpilocal, ila_mpiglobal
3028
3029    jdim = 0
3030    hiControlVector_out(:,:,:) = 0.0d0
3031    do jlev = 1, nkgdimSqrt
3032      do jm = mymBeg, mymEnd, mymSkip
3033        do jn = mynBeg, mynEnd, mynSkip
3034          if(jm.le.jn) then
3035            ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
3036            ila_mpilocal  = ilaList_mpilocal(ila_mpiglobal)
3037            if(jm == 0) then
3038              ! only real component for jm=0
3039              jdim = jdim + 1
3040              hiControlVector_out(ila_mpilocal,1,jlev) = controlVector_in(jdim)
3041            else
3042              ! both real and imaginary components for jm>0
3043              jdim = jdim + 1
3044              hiControlVector_out(ila_mpilocal,1,jlev) = controlVector_in(jdim)
3045              jdim = jdim + 1
3046              hiControlVector_out(ila_mpilocal,2,jlev) = controlVector_in(jdim)
3047            endif
3048          endif
3049        enddo
3050      enddo
3051    enddo
3052
3053  end SUBROUTINE BHI_cain
3054
3055
3056  SUBROUTINE BHI_cainAd(hiControlVector_in,controlVector_out)
3057    IMPLICIT NONE
3058
3059    ! Arguments:
3060    real(8), intent(out) :: controlVector_out(cvDim_mpilocal)
3061    real(8), intent(in)  :: hiControlVector_in(nla_mpilocal,2,nkgdimSqrt)
3062
3063    ! Locals:
3064    integer :: jdim, jlev, jm, jn, ila_mpilocal, ila_mpiglobal
3065
3066    jdim = 0
3067    do jlev = 1, nkgdimSqrt
3068      do jm = mymBeg, mymEnd, mymSkip
3069        do jn = mynBeg, mynEnd, mynSkip
3070          if(jm.le.jn) then
3071            ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
3072            ila_mpilocal  = ilaList_mpilocal(ila_mpiglobal)
3073            if(jm == 0) then
3074              ! only real component for jm=0
3075              jdim = jdim + 1
3076              controlVector_out(jdim) = controlVector_out(jdim) + hiControlVector_in(ila_mpilocal,1,jlev)
3077            else
3078              ! both real and imaginary components for jm>0
3079              jdim = jdim + 1
3080              controlVector_out(jdim) = controlVector_out(jdim) + hiControlVector_in(ila_mpilocal,1,jlev)*2.0d0
3081              jdim = jdim + 1
3082              controlVector_out(jdim) = controlVector_out(jdim) + hiControlVector_in(ila_mpilocal,2,jlev)*2.0d0
3083            endif
3084          endif
3085        enddo
3086      enddo
3087    enddo
3088
3089  END SUBROUTINE BHI_cainAd
3090
3091
3092  SUBROUTINE BHI_SPA2GD(hiControlVector_in,gd_out)
3093    IMPLICIT NONE
3094
3095    ! Arguments:
3096    real(8), intent(in)  :: hiControlVector_in(nla_mpilocal,2,nkgdimSqrt)
3097    real(8), intent(out) :: gd_out(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim)
3098
3099    ! Locals:
3100    real(8) :: sptb(nla_mpilocal,2,nlev_T_even),sp(nla_mpilocal,2,nkgdim)
3101    real(8) :: tb0(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nlev_T_even)
3102    integer :: jn,jm,ila_mpilocal,ila_mpiglobal,icount
3103    real(8) :: sq2, zp
3104    real(8) , allocatable :: zsp(:,:,:), zsp2(:,:,:)
3105    integer :: jlev, jlon, jlat, jla_mpilocal, klatPtoT
3106    real(8), pointer :: zgdpsi(:,:,:),zgdchi(:,:,:)
3107    real(8), target  :: gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim)
3108    real(8) :: dla2, dl1sa2, zcoriolis, zpsb(myLonBeg:myLonEnd,myLatBeg:myLatEnd)
3109
3110    klatPtoT = 1
3111
3112    ! maybe not needed:
3113    sp(:,:,:) = 0.0d0
3114    sptb(:,:,:) = 0.0d0
3115
3116    sq2 = sqrt(2.0d0)
3117    allocate(zsp(nkgdimSqrt,2,mymCount))
3118    allocate(zsp2(nkgdim2,2,mymCount))
3119    !$OMP PARALLEL DO PRIVATE(jn,jm,jlev,ila_mpiglobal,ila_mpilocal,zsp2,zsp,icount)
3120    do jn = mynBeg, mynEnd, mynSkip
3121
3122      icount = 0
3123      do jm = mymBeg, mymEnd, mymSkip
3124        if(jm.le.jn) then
3125          icount = icount+1
3126          ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
3127          ila_mpilocal = ilaList_mpilocal(ila_mpiglobal)
3128          do jlev = 1, nkgdimSqrt
3129            zsp(jlev,1,icount) = hiControlVector_in(ila_mpilocal,1,jlev)
3130            zsp(jlev,2,icount) = hiControlVector_in(ila_mpilocal,2,jlev)
3131          enddo
3132        endif
3133      enddo
3134
3135      if(icount.gt.0) then
3136
3137        CALL DGEMM('N','N',nkgdim2,2*icount,nkgdimSqrt,1.0d0,corns(1,1,jn),nkgdim2,zsp(1,1,1),nkgdimSqrt,0.0d0,zsp2(1,1,1),nkgdim2)
3138
3139        icount = 0
3140        do jm = mymBeg, mymEnd, mymSkip
3141          if(jm.le.jn) then
3142            icount = icount+1
3143            ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
3144            ila_mpilocal = ilaList_mpilocal(ila_mpiglobal)
3145            do jlev = 1, nkgdim
3146              sp(ila_mpilocal,1,jlev) = zsp2(jlev,1,icount)
3147              sp(ila_mpilocal,2,jlev) = zsp2(jlev,2,icount)
3148            enddo
3149            do jlev = 1, nlev_T
3150              sptb(ila_mpilocal,1,jlev) = zsp2(jlev+nkgdim,1,icount)
3151              sptb(ila_mpilocal,2,jlev) = zsp2(jlev+nkgdim,2,icount)
3152            enddo
3153          endif
3154        enddo
3155
3156      endif
3157
3158      ! make adjustments for jm=0
3159      if(mymBeg == 0) then
3160
3161        ila_mpiglobal = gst_getNind(0,gstID) + jn
3162        ila_mpilocal = ilaList_mpilocal(ila_mpiglobal)
3163
3164        do jlev = 1, nkgdim
3165          sp(ila_mpilocal,1,jlev) = sp(ila_mpilocal,1,jlev)*sq2
3166          sp(ila_mpilocal,2,jlev) = 0.0d0
3167        enddo
3168        do jlev = 1, nlev_T
3169          sptb(ila_mpilocal,1,jlev) = sptb(ila_mpilocal,1,jlev)*sq2
3170          sptb(ila_mpilocal,2,jlev) = 0.0d0
3171        enddo
3172
3173      endif
3174
3175    enddo
3176    !$OMP END PARALLEL DO
3177    deallocate(zsp)
3178    deallocate(zsp2)
3179
3180    !$OMP PARALLEL DO PRIVATE(JLAT,JLEV,JLON)
3181    do jlev = 1, nkgdim
3182      do jlat = myLatBeg, myLatEnd
3183        do jlon = myLonBeg, myLonEnd
3184          gd(jlon,jlat,jlev) = 0.0d0
3185        enddo
3186      enddo
3187    enddo
3188    !$OMP END PARALLEL DO
3189
3190    !$OMP PARALLEL DO PRIVATE(JLAT,JLEV,JLON)
3191    do jlev = 1, nlev_T_even
3192      do jlat = myLatBeg, myLatEnd
3193        do jlon = myLonBeg, myLonEnd
3194          tb0(jlon,jlat,jlev) = 0.0d0
3195        enddo
3196      enddo
3197    enddo
3198    !$OMP END PARALLEL DO
3199
3200    call gst_setID(gstID)
3201    call gst_speree(sp,gd)
3202    call gst_setID(gstID2)
3203    call gst_speree(sptb,tb0)
3204
3205    !$OMP PARALLEL DO PRIVATE(jlat,zcoriolis,jlev,jlon,zp)
3206    do jlat = myLatBeg, myLatEnd
3207      zcoriolis = 2.d0*ec_Omega*gst_getRmu(jlat,gstID)
3208      do jlon = myLonBeg, myLonEnd
3209        zpsb(jlon,jlat) = 0.0d0
3210        do jlev = 1, nlevPtoT
3211         zp = zcoriolis*gd(jlon,jlat,nspositVO+jlev-1)
3212         zpsb(jlon,jlat) = zpsb(jlon,jlat) + PtoT(nlev_T+1,jlev,klatPtoT)*zp
3213        enddo
3214      enddo
3215
3216      do jlev = 1, nlev_T
3217        do jlon = myLonBeg, myLonEnd
3218          tb0(jlon,jlat,jlev) = zcoriolis*tb0(jlon,jlat,jlev)
3219        enddo
3220      enddo
3221
3222      do jlev = 1, nkgdim
3223        do jlon = myLonBeg, myLonEnd
3224          if(jlev.ne.nspositTG) then
3225            gd(jlon,jlat,jlev) = gd(jlon,jlat,jlev)*rgsig(jlat,jlev)
3226          else
3227            gd(jlon,jlat,jlev) = gd(jlon,jlat,jlev)*tgstdbg(jlon,jlat)
3228          endif
3229        enddo
3230      enddo
3231
3232      do jlev = 1, nlev_T
3233        do jlon = myLonBeg, myLonEnd
3234          tb0(jlon,jlat,jlev) = tb0(jlon,jlat,jlev)*rgsigtb(jlat,jlev)
3235          gd(jlon,jlat,nspositTT+jlev-1) = gd(jlon,jlat,nspositTT+jlev-1)+tb0(jlon,jlat,jlev)
3236        enddo
3237      enddo
3238      do jlon = myLonBeg, myLonEnd
3239        zpsb(jlon,jlat) = zpsb(jlon,jlat)*rgsigpsb(jlat)
3240        gd(jlon,jlat,nspositPS) = gd(jlon,jlat,nspositPS)+zpsb(jlon,jlat)
3241      enddo
3242    enddo  ! jlat
3243    !$OMP END PARALLEL DO
3244
3245    zgdpsi(myLonBeg:,myLatBeg:,1:) => gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nspositVO:(nspositVO+nlev_M-1))
3246    zgdchi(myLonBeg:,myLatBeg:,1:) => gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nspositDI:(nspositDI+nlev_M-1))
3247    !$OMP PARALLEL DO PRIVATE(jlat,jlev,jlon)
3248    do jlev = nlev_bdl, nlev_M
3249      do jlat = myLatBeg, myLatEnd
3250        do jlon = myLonBeg, myLonEnd
3251          zgdchi(jlon,jlat,jlev) = zgdchi(jlon,jlat,jlev) - tantheta(jlev,jlat)*zgdpsi(jlon,jlat,jlev)
3252        enddo
3253      enddo
3254    enddo
3255    !$OMP END PARALLEL DO
3256
3257    sp(:,:,:) = 0.0d0
3258
3259    call gst_setID(gstID)
3260    call gst_reespe(sp,gd)
3261
3262    dla2   = ec_ra * ec_ra
3263    dl1sa2 = 1.d0/dla2
3264    !$OMP PARALLEL DO PRIVATE(JLEV,JLA_MPILOCAL,ILA_MPIGLOBAL)
3265    do jlev = 1, nlev_M
3266      do jla_mpilocal = 1, nla_mpilocal
3267        ila_mpiglobal = ilaList_mpiglobal(jla_mpilocal)
3268        sp(jla_mpilocal,1,nspositVO+jlev-1) = sp(jla_mpilocal,1,nspositVO+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3269        sp(jla_mpilocal,2,nspositVO+jlev-1) = sp(jla_mpilocal,2,nspositVO+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3270        sp(jla_mpilocal,1,nspositDI+jlev-1) = sp(jla_mpilocal,1,nspositDI+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3271        sp(jla_mpilocal,2,nspositDI+jlev-1) = sp(jla_mpilocal,2,nspositDI+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3272      enddo
3273    enddo
3274    !$OMP END PARALLEL DO
3275
3276    !$OMP PARALLEL DO PRIVATE(JLAT,JLEV,JLON)
3277    do jlev = 1, nkgdim
3278      do jlat = myLatBeg, myLatEnd
3279        do jlon = myLonBeg, myLonEnd
3280          gd(jlon,jlat,jlev) = 0.0d0
3281        enddo
3282      enddo
3283    enddo
3284    !$OMP END PARALLEL DO
3285
3286    call gst_setID(gstID)
3287    call gst_spgd(sp,gd,nlev_M)
3288
3289    !$OMP PARALLEL DO PRIVATE(JLAT,JLEV,JLON)
3290    do jlev = 1, nkgdim
3291      do jlat = myLatBeg, myLatEnd
3292        do jlon = myLonBeg, myLonEnd
3293          gd_out(jlon,jlat,jlev) = gd(jlon,jlat,jlev)
3294        enddo
3295      enddo
3296    enddo
3297    !$OMP END PARALLEL DO
3298
3299  END SUBROUTINE BHI_SPA2GD
3300
3301
3302  SUBROUTINE BHI_SPA2GDAD(gd_in,hiControlVector_out)
3303    implicit none
3304
3305    ! Arguments:
3306    real(8), intent(inout) :: hiControlVector_out(nla_mpilocal,2,nkgdimSqrt)
3307    real(8), intent(in)    :: gd_in(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim)
3308
3309    ! Locals:
3310    real(8) :: sptb(nla_mpilocal,2,nlev_T_even)
3311    real(8) :: sp(nla_mpilocal,2,nkgdim)
3312    real(8) :: tb0(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nlev_T_even)
3313    integer :: jn, jm, ila_mpilocal, ila_mpiglobal, icount
3314    real(8) :: sq2, zp
3315    real(8) ,allocatable :: zsp(:,:,:), zsp2(:,:,:)
3316    integer :: jlev, jlon, jlat, jla_mpilocal, klatPtoT
3317    real(8) :: dl1sa2, dla2, zcoriolis, zpsb(myLonBeg:myLonEnd,myLatBeg:myLatEnd)
3318    real(8),pointer :: zgdpsi(:,:,:) ,zgdchi(:,:,:)
3319    real(8), target :: gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nkgdim)
3320
3321    klatPtoT = 1
3322
3323    !$OMP PARALLEL DO PRIVATE(JLAT,JLEV,JLON)
3324    do jlev = 1, nkgdim
3325      do jlat = myLatBeg, myLatEnd
3326        do jlon = myLonBeg, myLonEnd
3327          gd(jlon,jlat,jlev) = gd_in(jlon,jlat,jlev)
3328        enddo
3329      enddo
3330    enddo
3331    !$OMP END PARALLEL DO
3332
3333    call gst_setID(gstID)
3334    call gst_spgda(sp,gd,nlev_M)
3335
3336    dla2   = ec_ra * ec_ra
3337    dl1sa2 = 1.d0/dla2
3338    !$OMP PARALLEL DO PRIVATE(JLEV,JLA_MPILOCAL,ILA_MPIGLOBAL)
3339    do jlev = 1, nlev_M
3340      do jla_mpilocal = 1, nla_mpilocal
3341        ila_mpiglobal = ilaList_mpiglobal(jla_mpilocal)
3342        sp(jla_mpilocal,1,nspositVO+jlev-1) = sp(jla_mpilocal,1,nspositVO+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3343        sp(jla_mpilocal,2,nspositVO+jlev-1) = sp(jla_mpilocal,2,nspositVO+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3344        sp(jla_mpilocal,1,nspositDI+jlev-1) = sp(jla_mpilocal,1,nspositDI+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3345        sp(jla_mpilocal,2,nspositDI+jlev-1) = sp(jla_mpilocal,2,nspositDI+jlev-1)*dl1sa2*gst_getrnnp1(ila_mpiglobal,gstID)
3346      enddo
3347    enddo
3348    !$OMP END PARALLEL DO
3349
3350    call gst_setID(gstID)
3351    call gst_speree(sp,gd)
3352
3353    zgdpsi(myLonBeg:,myLatBeg:,1:) => gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nspositVO:(nspositVO+nlev_M-1))
3354    zgdchi(myLonBeg:,myLatBeg:,1:) => gd(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nspositDI:(nspositDI+nlev_M-1))
3355    !$OMP PARALLEL DO PRIVATE(jlat,jlev,jlon)
3356    do jlev = nlev_bdl, nlev_M
3357      do jlat = myLatBeg, myLatEnd
3358        do jlon = myLonBeg, myLonEnd
3359          zgdpsi(jlon,jlat,jlev) = zgdpsi(jlon,jlat,jlev) - tantheta(jlev,jlat)*zgdchi(jlon,jlat,jlev)
3360        enddo
3361      enddo
3362    enddo
3363    !$OMP END PARALLEL DO
3364
3365    !$OMP PARALLEL DO PRIVATE(jlat,zcoriolis,jlev,jlon,zp)
3366    do jlat = myLatBeg, myLatEnd
3367      zcoriolis = 2.d0*ec_Omega*gst_getRMU(jlat,gstID)
3368      tb0(:,jlat,:) = 0.0d0
3369      do jlev = 1, nlev_T
3370        do jlon = myLonBeg, myLonEnd
3371          tb0(jlon,jlat,jlev) = gd(jlon,jlat,nspositTT+jlev-1)
3372          tb0(jlon,jlat,jlev) = tb0(jlon,jlat,jlev)*rgsigtb(jlat,jlev)
3373        enddo
3374      enddo
3375      do jlon = myLonBeg, myLonEnd
3376        zpsb(jlon,jlat) = gd(jlon,jlat,nspositPS)
3377        zpsb(jlon,jlat) = zpsb(jlon,jlat)*rgsigpsb(jlat)
3378      enddo
3379
3380      do jlev = 1, nkgdim
3381        do jlon = myLonBeg, myLonEnd
3382          if(jlev.ne.nspositTG) then
3383            gd(jlon,jlat,jlev) = gd(jlon,jlat,jlev)*rgsig(jlat,jlev)
3384          else
3385            gd(jlon,jlat,nspositTG) = gd(jlon,jlat,nspositTG)*tgstdbg(jlon,jlat)
3386          endif
3387        enddo
3388      enddo
3389
3390      do jlev = 1, nlev_T
3391        do jlon = myLonBeg, myLonEnd
3392          tb0(jlon,jlat,jlev) = zcoriolis*tb0(jlon,jlat,jlev)
3393        enddo
3394      enddo
3395
3396      do jlev = 1, nlevPtoT
3397        do jlon = myLonBeg, myLonEnd
3398          zp = PtoT(nlev_T+1,jlev,klatPtoT)*zpsb(jlon,jlat)
3399          gd(jlon,jlat,nspositVO+jlev-1) = zcoriolis*zp+gd(jlon,jlat,nspositVO+jlev-1)
3400        enddo
3401      enddo
3402    enddo
3403    !$OMP END PARALLEL DO 
3404
3405    call gst_setID(gstID)
3406    call gst_reespe(sp,gd)
3407    call gst_setID(gstID2)
3408    call gst_reespe(sptb,tb0)
3409
3410    hiControlVector_out(:,:,:) = 0.0d0
3411    sq2 = sqrt(2.0d0)
3412    allocate(zsp(nkgdimSqrt,2,mymCount))
3413    allocate(zsp2(nkgdim2,2,mymCount))
3414    !$OMP PARALLEL DO PRIVATE(JN,JM,JLEV,ILA_MPILOCAL,ILA_MPIGLOBAL,zsp,zsp2,icount)
3415    do jn = mynBeg, mynEnd, mynSkip
3416
3417      icount = 0
3418      do jm = mymBeg, mymEnd, mymSkip
3419        if(jm.le.jn) then
3420          icount = icount+1
3421          ila_mpiglobal = gst_getNind(jm,gstID) + jn - jm
3422          ila_mpilocal = ilaList_mpilocal(ila_mpiglobal)
3423          do jlev = 1, nkgdim
3424            zsp2(jlev,1,icount) = sp(ila_mpilocal,1,jlev)
3425            zsp2(jlev,2,icount) = sp(ila_mpilocal,2,jlev)
3426          enddo
3427          do jlev = 1, nlev_T
3428            zsp2(jlev+nkgdim,1,icount) = sptb(ila_mpilocal,1,jlev)
3429            zsp2(jlev+nkgdim,2,icount) = sptb(ila_mpilocal,2,jlev)
3430          enddo
3431        endif
3432      enddo
3433
3434      if(icount.gt.0) then
3435
3436        CALL DGEMM('T','N',nkgdimSqrt,2*icount,nkgdim2,1.0d0,corns(1,1,jn),nkgdim2,zsp2(1,1,1),nkgdim2,0.0d0,zsp(1,1,1),nkgdimSqrt)
3437
3438        icount = 0
3439        do jm = mymBeg, jn, mymSkip
3440          icount=icount+1
3441          ila_mpiglobal = gst_getNIND(jm,gstID) + jn - jm
3442          ila_mpilocal = ilaList_mpilocal(ila_mpiglobal)
3443          do jlev = 1, nkgdimSqrt
3444            hiControlVector_out(ila_mpilocal,1,jlev) = zsp(jlev,1,icount)
3445            hiControlVector_out(ila_mpilocal,2,jlev) = zsp(jlev,2,icount)
3446          enddo
3447        enddo
3448
3449      endif
3450
3451      ! make adjustments for jm=0
3452      if(mymBeg == 0) then
3453
3454        ila_mpiglobal = gst_getNIND(0,gstID) + jn
3455        ila_mpilocal = ilaList_mpilocal(ila_mpiglobal)
3456
3457        do jlev = 1, nkgdimSqrt
3458          hiControlVector_out(ila_mpilocal,1,jlev) = hiControlVector_out(ila_mpilocal,1,jlev)*sq2
3459          hiControlVector_out(ila_mpilocal,2,jlev) = hiControlVector_out(ila_mpilocal,2,jlev)*sq2
3460        enddo
3461
3462      endif
3463
3464    enddo
3465    !$OMP END PARALLEL DO
3466    deallocate(zsp)
3467    deallocate(zsp2)
3468
3469  END SUBROUTINE BHI_SPA2GDAD
3470
3471
3472  SUBROUTINE BHI_Finalize()
3473    implicit none
3474
3475    if (initialized) then
3476       deallocate(pressureProfile_M)
3477       deallocate(pressureProfile_T)
3478       deallocate(PtoT)
3479       deallocate(tantheta)
3480       deallocate(rgsig)
3481       deallocate(tgstdbg)
3482       deallocate(rgsigtb)
3483       deallocate(rgsigpsb)
3484       deallocate(corns)
3485       deallocate(rstddev)
3486    end if
3487
3488  END SUBROUTINE BHI_Finalize
3489
3490END MODULE bMatrixHI_mod