lamAnalysisGridTransforms_mod sourceΒΆ

   1module lamAnalysisGridTransforms_mod
   2  ! MODULE lamAnalysisGridTransforms_mod (prefix='lgt' category='7. Low-level data objects')
   3  !
   4  !:Purpose:  Performs some horizontal grid-point variable transforms 
   5  !           for the limited-area computational analysis grids (extended and
   6  !           non-extended).
   7  !
   8  use earthConstants_mod
   9  use mathPhysConstants_mod
  10  use horizontalCoord_mod
  11  use verticalCoord_mod
  12  use midasMpi_mod
  13  use utilities_mod
  14  use Vgrid_Descriptors
  15  implicit none
  16  save
  17  private
  18
  19  ! public procedures
  20  public :: lgt_setupFromHCO, lgt_mach, lgt_mach_r4
  21  public :: lgt_PsiChiToUV, lgt_PsiChiToUVAdj, lgt_UVToVortDiv
  22  public :: lgt_createLamTemplateGrids
  23
  24  ! Definition of some parameters characterizing the geometry of
  25  ! the Limited-Area (LA) analysis grid and associated metric factors
  26  type :: struct_glmf
  27     real(8), allocatable :: rlat   (:) ! Latitudes of Scalar gridpoints
  28     real(8), allocatable :: rlon   (:) ! Longitudes of Scalar gridpoints
  29     real(8)              :: rdlon      ! Latitude difference of gridpoints
  30     real(8)              :: rdlat      ! Longitude differences of gridpoints
  31     real(8), allocatable :: cos2 (:)   ! Grid metric for Psi-Chi to U-V
  32     real(8), allocatable :: cos2h(:)   ! Grid metric for Psi-Chi to U-V
  33     real(8), allocatable :: cos2vd (:) ! Grid metric for U-V to Vort-Div
  34     real(8), allocatable :: cos2hvd(:) ! Grid metric for U-V to Vort-Div
  35     real(8), allocatable :: idmuh(:)   ! Grid metric for U-V to Vort-Div
  36     real(8), allocatable :: idmu (:)   ! Grid metric for U-V to Vort-Div
  37     real(8)              :: dx         ! Grid-point spacing (uniform)
  38     real(8), allocatable :: conphy (:) ! to go from Wind Images to true winds
  39     real(8), allocatable :: conima (:) ! to go from true winds to Wind Images
  40  end type struct_glmf
  41
  42  type(struct_hco), pointer :: hco_core => null()
  43  type(struct_hco), pointer :: hco_ext => null()
  44  type(struct_glmf):: glmf
  45
  46  integer :: ni_ext, nj_ext   ! With    Extension for Bi-Fourrier
  47  integer :: ni_core, nj_core ! Without Extension for Bi-Fourrier
  48  integer :: ext_i , ext_j    ! Extension gridpoints
  49
  50  integer :: ni_ext_per, nj_ext_per
  51
  52  integer :: istart, iend, jstart, jend
  53
  54  integer :: LonPerPE, LonPerPEmax, myLonBeg, myLonEnd
  55  integer :: LatPerPE, LatPerPEmax, myLatBeg, myLatEnd
  56
  57  logical :: initialized = .false.
  58
  59contains
  60
  61  !--------------------------------------------------------------------------
  62  ! lgt_SetupFromHCO
  63  !--------------------------------------------------------------------------
  64  subroutine lgt_SetupFromHCO( hco_ext_in, hco_core_opt )
  65    implicit none
  66
  67    ! Arguments:
  68    type(struct_hco), pointer,           intent(in) :: hco_ext_in
  69    type(struct_hco), pointer, optional, intent(in) :: hco_core_opt
  70
  71    ! Locals:
  72    real(8), allocatable :: rlath  (:) ! Latitudes of half grid-points of gridpoints in lat-direction
  73    real(8), allocatable :: rrcos  (:) ! 1.0/Cos(Latitudes of gridpoints)
  74    real(8), allocatable :: rdmu   (:) ! Differences of mu=sin(lat)
  75    real(8), allocatable :: rdmuh  (:) ! Differences of muh=sin(lath)
  76    real(8), allocatable :: r1mmu2 (:) ! (1.-mu**2)
  77    real(8), allocatable :: r1mmu2h(:) ! (1.-muh**2)
  78
  79    real(8) :: dlon_test, dlat_test, dlon_ref, dlat_ref
  80
  81    integer :: i, j
  82
  83    logical, save :: firstCall = .true.
  84
  85    ! Ensure subroutine only runs one time during program execution
  86    if (firstCall) then
  87      firstCall = .false.
  88    else
  89      return
  90    end if
  91
  92    write(*,*)
  93    write(*,*) 'lgt_SetupFromHCO: Starting...'
  94
  95    initialized = .true.
  96
  97    !
  98    !- 1.  Check the hco structures
  99    !
 100    hco_ext  => hco_ext_in
 101    if( present(hco_core_opt) ) then
 102      hco_core => hco_core_opt
 103    else
 104      hco_core => hco_ext_in
 105    end if
 106
 107    if ( (.not. hco_core%initialized) .or.  & 
 108         (.not. hco_ext%initialized) ) then
 109      write(*,*)
 110      write(*,*) 'lgt_SetupFromHCO: At least one hco structure was not initilzed'
 111      write(*,*) 'hco_core = ', hco_core%initialized
 112      write(*,*) 'hco_ext = ', hco_ext%initialized
 113      call utl_abort('lgt_SetupFromHCO: abort')
 114    end if
 115
 116    if ( (hco_core%global) .or.  & 
 117         (hco_ext%global) ) then
 118      write(*,*)
 119      write(*,*) 'lgt_SetupFromHCO: At least one hco structure is from a global grid, skipping rest of setup'
 120      write(*,*) 'hco_core = ', hco_core%global
 121      write(*,*) 'hco_ext = ', hco_ext%global
 122      return
 123    end if
 124
 125    !
 126    !- 2.  Dimension settings and Memory allocation
 127    !
 128
 129    !- 2.1 Dimensions
 130    ni_core = hco_core%ni
 131    nj_core = hco_core%nj
 132
 133    ni_ext = hco_ext%ni
 134    nj_ext = hco_ext%nj
 135
 136    ext_i  = ni_ext - ni_core
 137    ext_j  = nj_ext - nj_core
 138
 139    if ( ext_i == 0 .and. ext_j == 0 ) then
 140      write(*,*)
 141      write(*,*) 'lgt_SetupFromHCO: LAM core and extended grids are identical'
 142    else if ( ext_i < 10 .or. ext_j < 10 ) then
 143      write(*,*)
 144      write(*,*) 'lgt_SetupFromHCO: LAM domain extension is less than 10 gridpoints'
 145      write(*,*) ' ext_i = ', ext_i,' ext_j = ', ext_j
 146    end if
 147
 148    ni_ext_per = ni_ext + 1  ! Fields will be periodic (i = 1 repeated) at ni_ext+1
 149    nj_ext_per = nj_ext + 1  ! Fields will be periodic (j = 1 repeated) at nj_ext+1
 150
 151    !- 2.2 First Make sure we have a uniform grid in x and y direction
 152
 153    !- 2.2.1 Analysis core grid
 154    dlon_ref = hco_core%lon(2) - hco_core%lon(1)
 155    do i = 2, ni_core
 156      dlon_test = hco_core%lon(i) - hco_core%lon(i-1)
 157      if ( (dlon_test - dlon_ref) > dlon_ref/100.0d0 ) then
 158        write(*,*)
 159        write(*,*) 'lgt_SetupFromHCO: Core grid spacing is not uniform in x-direction'
 160        write(*,*) ' i         = ', i
 161        write(*,*) ' dlon      = ', dlon_test
 162        write(*,*) ' dlon ref  = ', dlon_ref
 163        call utl_abort('lgt_SetupFromHCO')
 164      end if
 165    end do
 166
 167    dlat_ref = hco_core%lat(2) - hco_core%lat(1)
 168    do j = 2, nj_core
 169      dlat_test = hco_core%lat(j) - hco_core%lat(j-1) 
 170      if ( (dlat_test - dlat_ref) > dlat_ref/100.0d0 ) then
 171        write(*,*)
 172        write(*,*) 'lgt_SetupFromHCO: Core grid spacing is not uniform in x-direction'
 173        write(*,*) ' j         = ', j
 174        write(*,*) ' dlat      = ', dlon_test
 175        write(*,*) ' dlat ref  = ', dlon_ref
 176        call utl_abort('lgt_SetupFromHCO') 
 177      end if
 178    end do
 179
 180    !- 2.2.2 Extended Analysis grid
 181    dlon_ref = hco_ext%lon(2) - hco_ext%lon(1)
 182    do i = 2, ni_ext
 183      dlon_test = hco_ext%lon(i) - hco_ext%lon(i-1)
 184      if ( (dlon_test - dlon_ref) > dlon_ref/100.0d0 ) then
 185        write(*,*)
 186        write(*,*) 'lgt_SetupFromHCO: Extended grid spacing is not uniform in x-direction'
 187        write(*,*) ' i         = ', i
 188        write(*,*) ' dlon      = ', dlon_test
 189        write(*,*) ' dlon ref  = ', dlon_ref
 190        call utl_abort('lgt_SetupFromHCO')
 191      end if
 192    end do
 193
 194    dlat_ref = hco_ext%lat(2) - hco_ext%lat(1)
 195    do j = 2, nj_ext
 196      dlat_test = hco_ext%lat(j) - hco_ext%lat(j-1)
 197      if ( (dlat_test - dlat_ref) > dlat_ref/100.0d0 ) then
 198        write(*,*)
 199        write(*,*) 'lgt_SetupFromHCO: Extended grid spacing is not uniform in x-direction'
 200        write(*,*) ' j         = ', j
 201        write(*,*) ' dlat      = ', dlon_test
 202        write(*,*) ' dlat ref  = ', dlon_ref
 203        call utl_abort('lgt_SetupFromHCO') 
 204      end if
 205    end do
 206
 207    !- 2.3 Dimensions for variables needed to be symmetric
 208    istart = -4          ! 5 gridpoints padding in West direction
 209    iend   = ni_ext + 4  ! 4 gridpoints padding in East direction
 210    jstart = -4          ! 5 gridpoints padding in South direction
 211    jend   = nj_ext + 4  ! 4 gridpoints padding in North direction
 212
 213    !- 2.4 Allocations
 214    allocate(glmf%rlon(istart:iend))
 215    allocate(glmf%rlat(jstart:jend))
 216    allocate(rlath    (jstart:jend))
 217    allocate(rrcos    (jstart:jend))
 218    allocate(rdmu     (jstart:jend))
 219    allocate(rdmuh    (jstart:jend))
 220    allocate(r1mmu2   (jstart:jend))
 221    allocate(r1mmu2h  (jstart:jend))
 222
 223    !
 224    !- 3.  Set Lat-Lon of the computational grid
 225    !
 226
 227    !  3.1 Set (constant) Grid spacing
 228    glmf%rdlon = (hco_ext%lon(2) - hco_ext%lon(1))
 229    glmf%rdlat = (hco_ext%lat(2) - hco_ext%lat(1))
 230
 231    !- 3.2 Lat-Lon
 232
 233    !  3.2.1 Extract the lat-lon from the extended grid
 234    glmf%rlon(1:ni_ext) = hco_ext%lon(1:ni_ext)
 235    glmf%rlat(1:nj_ext) = hco_ext%lat(1:nj_ext)
 236
 237    !  3.2.2 Extend to the full computational grid (larger than the extended grid!)
 238
 239    ! West
 240    do i = istart, 0
 241      glmf%rlon(i) = glmf%rlon(1) + (i-1) * glmf%rdlon
 242    end do
 243    ! East
 244    do i = ni_ext+1, iend
 245      glmf%rlon(i) = glmf%rlon(ni_ext) + (i-ni_ext) * glmf%rdlon
 246    end do
 247    ! North
 248    do j = nj_ext+1, jend
 249      glmf%rlat(j) = glmf%rlat(nj_ext) + (j-nj_ext) * glmf%rdlat
 250    end do
 251    ! South
 252    do j = jstart, 0
 253      glmf%rlat(j) = glmf%rlat(1) + (j-1) * glmf%rdlat
 254    end do
 255
 256    !- 3.2 Half Lat-Lon
 257    do j = jstart+1, jend-1
 258      rlath(j) = ( glmf%rlat(j) + glmf%rlat(j+1) ) / 2.0d0
 259    end do
 260
 261    !
 262    !- 4. Set Metric Factors
 263    !
 264
 265    !- 4.1  Compute local factors
 266    do j = jstart+1, jend-2
 267      rrcos  (j) = 1.0d0 / cos(glmf%rlat (j))
 268      rdmu   (j) = sin(glmf%rlat (j+1)) - sin(glmf%rlat (j))
 269      rdmuh  (j) = sin(rlath(j+1)) - sin(rlath(j))
 270      r1mmu2 (j) = (cos(glmf%rlat (j)))**2
 271      r1mmu2h(j) = (cos(rlath(j)))**2
 272    end do
 273
 274    !- 4.2  Bi-periodize and symmetrize Metric coefficients
 275    call lgt_mach(rdmu   (1:nj_ext), & ! INOUT
 276                   1, nj_ext,1)        ! IN
 277    call lgt_mach(rdmuh  (1:nj_ext), & ! INOUT
 278                   1, nj_ext,1)        ! IN 
 279    call lgt_mach(r1mmu2 (1:nj_ext), & ! INOUT
 280                   1, nj_ext,1)        ! IN
 281    call lgt_mach(r1mmu2h(1:nj_ext), & ! INOUT
 282                   1, nj_ext,1)        ! IN
 283
 284    call symmetrize_coef(rdmu   ) ! INOUT
 285    call symmetrize_coef(rdmuh  ) ! INOUT
 286    call symmetrize_coef(r1mmu2 ) ! INOUT
 287    call symmetrize_coef(r1mmu2h) ! INOUT
 288
 289    !- 4.3 Compute global factors
 290    glmf%dx  = 1.d0 / (ec_ra * glmf%rdlon)
 291
 292    allocate(glmf%cos2   ( 0:nj_ext+1))
 293    allocate(glmf%cos2h  ( 0:nj_ext+1))
 294    do j = 0, nj_ext+1
 295      glmf%cos2 (j) = r1mmu2 (j) / (ec_ra * rdmuh(j-1))
 296      glmf%cos2h(j) = r1mmu2h(j) / (ec_ra * rdmu (j  ))
 297    end do
 298
 299    allocate(glmf%idmuh  (0:nj_ext-1))
 300    allocate(glmf%idmu   (1:nj_ext  ))
 301    allocate(glmf%cos2vd (1:nj_ext  ))
 302    allocate(glmf%cos2hvd(1:nj_ext  ))
 303
 304    do j = 1, nj_ext
 305      glmf%idmuh  (j-1) = 1.d0 / rdmuh(j-1)
 306      glmf%idmu   (j)   = 1.d0 / rdmu   (j)
 307      glmf%cos2vd (j)   = 1.d0 / r1mmu2 (j)
 308      glmf%cos2hvd(j)   = 1.d0 / r1mmu2h(j)
 309    end do
 310
 311    !
 312    ! Conversion of wind images to physical winds and vice-versa
 313    ! N.B.: Those are geometrical factors of the COMPUTATIONAL grid 
 314    !        ==> only computational latitude variation...
 315    !
 316    allocate(glmf%conphy(nj_ext))
 317    allocate(glmf%conima(nj_ext))
 318
 319    call lgt_mach(rrcos(1:nj_ext),  & ! INOUT
 320                  1, nj_ext,1)        ! IN
 321
 322    do j = 1, nj_ext
 323      glmf%conphy(j) = rrcos(j)                ! to go from Wind Images to true winds
 324      glmf%conima(j) = 1.0d0 / glmf%conphy(j)  ! to go from true winds to Wind Images
 325    end do
 326
 327    !
 328    !- 5. MPI partitionning
 329    !
 330    if ( mmpi_nprocs /= 0 ) then
 331       call mmpi_setup_lonbands(ni_ext,                      & ! IN
 332                                lonPerPE, lonPerPEmax, myLonBeg, myLonEnd ) ! OUT
 333
 334       call mmpi_setup_latbands(nj_ext,                      & ! IN
 335                                latPerPE, latPerPEmax, myLatBeg, myLatEnd ) ! OUT
 336    else
 337       ! This option is needed for the biper program
 338       lonPerPE = ni_ext
 339       myLonBeg = 1
 340       myLonEnd = ni_ext
 341       latPerPE = nj_ext
 342       myLatBeg = 1
 343       myLatEnd = nj_ext
 344       write(*,*)
 345       write(*,*) 'WARNING: the module will be executed in NO-MPI MODE!'
 346    end if
 347
 348    !
 349    !- 6.  Ending
 350    !
 351    deallocate(rlath  )
 352    deallocate(rrcos  )
 353    deallocate(rdmu   )
 354    deallocate(rdmuh  )
 355    deallocate(r1mmu2 )
 356    deallocate(r1mmu2h)
 357
 358    write(*,*)
 359    write(*,*) 'lgt_SetupFromHCO: Done!'
 360
 361  end subroutine lgt_SetupFromHCO
 362
 363  !--------------------------------------------------------------------------
 364  ! symmetrize_coef
 365  !--------------------------------------------------------------------------
 366  subroutine symmetrize_coef(coef_inout)
 367    !
 368    !:Purpose: Extend symmetrically Metric coefficients.
 369    !
 370    implicit none
 371
 372    ! Arguments:
 373    real(8), intent(inout) :: coef_inout(jstart:jend)
 374
 375    ! Locals:
 376    integer :: j
 377    
 378    do j = jstart, 0
 379      coef_inout(j) = coef_inout(nj_ext+j)
 380    end do
 381
 382    do j = nj_ext+1, jend
 383      coef_inout(j) = coef_inout(j-nj_ext) 
 384    end do
 385
 386  end subroutine symmetrize_coef
 387
 388  !--------------------------------------------------------------------------
 389  ! lgt_PsiChiToUV
 390  !--------------------------------------------------------------------------
 391  subroutine lgt_PsiChiToUV(psi, chi, uphy, vphy, nk)
 392    implicit none
 393
 394    ! Arguments:
 395    integer, intent(in)  :: nk
 396    real(8), intent(in)  :: psi(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 397    real(8), intent(in)  :: chi(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 398    real(8), intent(out) :: uphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 399    real(8), intent(out) :: vphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 400
 401    ! Locals:
 402    real(8), allocatable :: psi_ext(:,:,:)
 403    real(8), allocatable :: chi_ext(:,:,:)
 404    real(8), allocatable :: uimg(:,:,:)
 405    real(8), allocatable :: vimg(:,:,:)
 406    real(8), allocatable :: uimgs(:,:,:)
 407    real(8), allocatable :: vimgs(:,:,:)
 408    integer :: i,j,k
 409
 410    if ( hco_ext%global ) then
 411      call utl_abort('lgt_PsiChiToUV: Not compatible with global grid')
 412    endif
 413
 414    if ( .not. initialized ) then
 415      call utl_abort('lgt_PsiChiToUV: AnalysisGrid not initialized')
 416    endif
 417
 418    allocate(psi_ext( (myLonBeg-1):(myLonEnd+1), (myLatBeg-1):(myLatEnd+1), nk))
 419    allocate(chi_ext( (myLonBeg-1):(myLonEnd+1), (myLatBeg-1):(myLatEnd+1), nk))
 420    allocate(uimg   ( myLonBeg:myLonEnd        , myLatBeg:myLatEnd        , nk))
 421    allocate(vimg   ( myLonBeg:myLonEnd        , myLatBeg:myLatEnd        , nk))
 422    allocate(uimgs  ( (myLonBeg-1):myLonEnd    , myLatBeg:(myLatEnd+1)    , nk))
 423    allocate(vimgs  ( myLonBeg:(myLonEnd+1)    , (myLatBeg-1):myLatEnd    , nk))
 424
 425    !
 426    !- 1.  Symmetrize
 427    !
 428    call symmetrize( psi_ext,                                        & ! OUT
 429                     psi, myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 430    call symmetrize( chi_ext,                                        & ! OUT
 431                     chi, myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 432
 433    !
 434    !- 2.  Compute Wind on staggered grid
 435    !
 436
 437    !$OMP PARALLEL DO PRIVATE (k,j,i)
 438    do k = 1, nk
 439      !- 2.1 u-wind component
 440       do j = myLatBeg, myLatEnd+1
 441        do i = myLonBeg-1, myLonEnd
 442           uimgs(i,j,k) =   glmf%dx      * ( chi_ext(i+1,j,k) - chi_ext(i,j,k)   ) &
 443                          - glmf%cos2(j) * ( psi_ext(i,j,k)   - psi_ext(i,j-1,k) )
 444        end do
 445      end do
 446      !- 2.2 v-wind component
 447      do j = myLatBeg-1, myLatEnd
 448        do i = myLonBeg, myLonEnd+1
 449           vimgs(i,j,k) =   glmf%cos2h(j) * ( chi_ext(i,j+1,k) - chi_ext(i,j,k)   ) &
 450                          + glmf%dx       * ( psi_ext(i,j,k)   - psi_ext(i-1,j,k) )
 451        end do
 452      end do
 453    end do
 454    !$OMP END PARALLEL DO
 455
 456    !
 457    !- 3.  Move to collocated (scalar) grid
 458    !
 459    call uvStagToColloc( uimgs, vimgs,                              & ! IN
 460                         uimg , vimg ,                              & ! OUT
 461                         myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 462
 463    !
 464    !- 4.  Convert Wind images to Physical (true) winds
 465    !
 466    !$OMP PARALLEL DO PRIVATE (j)
 467    do j = myLatBeg, myLatEnd
 468      uphy(:,j,:) =  glmf%conphy(j) * uimg(:,j,:)
 469      vphy(:,j,:) =  glmf%conphy(j) * vimg(:,j,:)
 470    end do
 471    !$OMP END PARALLEL DO
 472
 473    deallocate(psi_ext)
 474    deallocate(chi_ext)
 475    deallocate(uimg)
 476    deallocate(vimg)
 477    deallocate(uimgs)
 478    deallocate(vimgs)
 479
 480  end subroutine lgt_PsiChiToUV
 481
 482  !--------------------------------------------------------------------------
 483  ! lgt_PsiChiToUVAdj
 484  !--------------------------------------------------------------------------
 485  subroutine lgt_PsiChiToUVAdj(psi, chi, uphy, vphy, nk)
 486    implicit none
 487
 488    ! Arguments:
 489    integer, intent(in)  :: nk
 490    real(8), intent(out) :: psi(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 491    real(8), intent(out) :: chi(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)    
 492    real(8), intent(in)  :: uphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 493    real(8), intent(in)  :: vphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 494
 495    ! Locals:
 496    real(8), allocatable :: psi_ext(:,:,:)
 497    real(8), allocatable :: chi_ext(:,:,:)
 498    real(8), allocatable :: uimg(:,:,:)
 499    real(8), allocatable :: vimg(:,:,:)
 500    real(8), allocatable :: uimgs(:,:,:)
 501    real(8), allocatable :: vimgs(:,:,:)
 502    integer :: i,j,k
 503
 504    if ( hco_ext%global ) then
 505      call utl_abort('lgt_PsiChiToUVAdj: Not compatible with global grid')
 506    endif
 507
 508    if ( .not. initialized ) then
 509      call utl_abort('lgt_PsiChiToUV: AnalysisGrid not initialized')
 510    endif
 511
 512    allocate(psi_ext( (myLonBeg-1):(myLonEnd+1), (myLatBeg-1):(myLatEnd+1), nk))
 513    allocate(chi_ext( (myLonBeg-1):(myLonEnd+1), (myLatBeg-1):(myLatEnd+1), nk))
 514    allocate(uimg   ( myLonBeg:myLonEnd        , myLatBeg:myLatEnd        , nk))
 515    allocate(vimg   ( myLonBeg:myLonEnd        , myLatBeg:myLatEnd        , nk))
 516    allocate(uimgs  ( (myLonBeg-1):myLonEnd    , myLatBeg:(myLatEnd+1)    , nk))
 517    allocate(vimgs  ( myLonBeg:(myLonEnd+1)    , (myLatBeg-1):myLatEnd    , nk))
 518
 519    !
 520    !- 4.  Convert Physical (true) winds to Wind images
 521    !
 522    !$OMP PARALLEL DO PRIVATE (j)
 523    do j = myLatBeg, myLatEnd
 524      uimg(:,j,:) =  glmf%conphy(j) * uphy(:,j,:)
 525      vimg(:,j,:) =  glmf%conphy(j) * vphy(:,j,:)
 526    end do
 527    !$OMP END PARALLEL DO
 528
 529    !
 530    !- 3.  Move to stagerred grid
 531    !
 532    uimgs(:,:,:) = 0.d0
 533    vimgs(:,:,:) = 0.d0
 534
 535    call uvStagToCollocAdj( uimgs, vimgs,                              & ! OUT
 536                            uimg , vimg ,                              & ! IN
 537                            myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 538
 539    !
 540    !- 2.  Compute Psi-Chi
 541    !
 542    chi_ext(:,:,:) = 0.d0
 543    psi_ext(:,:,:) = 0.d0
 544
 545    !$OMP PARALLEL DO PRIVATE (k,j,i)
 546    do k = 1, nk
 547      !- 2.2 from v-wind component
 548      do j = myLatEnd, myLatBeg-1, -1
 549        do i = myLonEnd+1, myLonBeg, -1
 550          chi_ext(i  ,j+1,k) = chi_ext(i  ,j+1,k) + vimgs(i,j,k) * glmf%cos2h(j)
 551          chi_ext(i  ,j  ,k) = chi_ext(i  ,j  ,k) - vimgs(i,j,k) * glmf%cos2h(j)
 552          psi_ext(i  ,j  ,k) = psi_ext(i  ,j  ,k) + vimgs(i,j,k) * glmf%dx
 553          psi_ext(i-1,j  ,k) = psi_ext(i-1,j  ,k) - vimgs(i,j,k) * glmf%dx
 554        end do
 555      end do
 556      !- 2.1 from u-wind component
 557      do j = myLatEnd+1, myLatBeg, -1
 558        do i = myLonEnd, myLonBeg-1, -1
 559          chi_ext(i+1,j  ,k) = chi_ext(i+1,j  ,k) + uimgs(i,j,k) * glmf%dx
 560          chi_ext(i  ,j  ,k) = chi_ext(i  ,j  ,k) - uimgs(i,j,k) * glmf%dx
 561          psi_ext(i  ,j  ,k) = psi_ext(i  ,j  ,k) - uimgs(i,j,k) * glmf%cos2(j)
 562          psi_ext(i  ,j-1,k) = psi_ext(i  ,j-1,k) + uimgs(i,j,k) * glmf%cos2(j)
 563        end do
 564     end do
 565    end do
 566    !$OMP END PARALLEL DO
 567
 568    !
 569    !- 1.  De-Symmetrize
 570    !
 571    chi(:,:,:) = 0.d0
 572    psi(:,:,:) = 0.d0
 573
 574    call symmetrizeAdj( psi_ext,                                   & ! IN
 575                        psi,                                       & ! OUT
 576                        myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 577    call symmetrizeAdj( chi_ext,                                   & ! IN
 578                        chi,                                       & ! OUT
 579                        myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 580
 581    deallocate(psi_ext)
 582    deallocate(chi_ext)
 583    deallocate(uimg)
 584    deallocate(vimg)
 585    deallocate(uimgs)
 586    deallocate(vimgs)
 587
 588  end subroutine lgt_PsiChiToUVAdj
 589
 590  !--------------------------------------------------------------------------
 591  ! uvStagToColloc
 592  !--------------------------------------------------------------------------
 593  subroutine uvStagToColloc(uStag, vStag, uColloc, vColloc, iBeg, iEnd, jBeg, jEnd , nk)
 594    implicit none
 595
 596    ! Arguments:
 597    integer, intent(in)  :: iBeg
 598    integer, intent(in)  :: iEnd
 599    integer, intent(in)  :: jBeg
 600    integer, intent(in)  :: JEnd
 601    integer, intent(in)  :: nk
 602    real(8), intent(out) :: uColloc(iBeg:iEnd  ,jBeg  :jEnd  ,nk)
 603    real(8), intent(out) :: vColloc(iBeg:iEnd  ,jBeg  :jEnd  ,nk)
 604    real(8), intent(in)  :: uStag  (iBeg-1:iEnd,jBeg  :jEnd+1,nk)
 605    real(8), intent(in)  :: vStag  (iBeg:iEnd+1,jBeg-1:jEnd  ,nk)
 606
 607    ! Locals:
 608    integer :: i,j,k
 609
 610    !$OMP PARALLEL DO PRIVATE (k,j,i)
 611    do k = 1, nk
 612      do j = jBeg, jEnd
 613        do i = iBeg, iEnd
 614          uColloc(i,j,k) = ( uStag(i-1,j  ,k) + uStag(i,j,k) ) / 2.0d0
 615          vColloc(i,j,k) = ( vStag(i  ,j-1,k) + vStag(i,j,k) ) / 2.0d0
 616        end do
 617      end do
 618    end do
 619    !$OMP END PARALLEL DO
 620
 621  end subroutine uvStagToColloc
 622
 623  !--------------------------------------------------------------------------
 624  ! uvStagToCollocAdj
 625  !--------------------------------------------------------------------------
 626  subroutine uvStagToCollocAdj(uStag, vStag, uColloc, vColloc, iBeg, iEnd, jBeg, jEnd , nk)
 627    implicit none
 628
 629    ! Arguments:
 630    integer, intent(in)  :: iBeg
 631    integer, intent(in)  :: iEnd
 632    integer, intent(in)  :: jBeg
 633    integer, intent(in)  :: jEnd
 634    integer, intent(in)  :: nk
 635    real(8), intent(in)  :: uColloc(iBeg:iEnd  ,jBeg  :jEnd  ,nk)
 636    real(8), intent(in)  :: vColloc(iBeg:iEnd  ,jBeg  :jEnd  ,nk)
 637    real(8), intent(out) :: uStag  (iBeg-1:iEnd,jBeg  :jEnd+1,nk)
 638    real(8), intent(out) :: vStag  (iBeg:iEnd+1,jBeg-1:jEnd  ,nk)
 639
 640    ! Locals:
 641    integer :: i, j, k
 642
 643    !$OMP PARALLEL DO PRIVATE (k,j,i)
 644    do k = 1, nk
 645      do j = jEnd, jBeg, -1
 646        do i = iEnd, iBeg, -1
 647          uStag(i-1,j  ,k) = uStag(i-1,j  ,k) + uColloc(i,j,k) / 2.0d0
 648          uStag(i  ,j  ,k) = uStag(i  ,j  ,k) + uColloc(i,j,k) / 2.0d0
 649          vStag(i  ,j-1,k) = vStag(i  ,j-1,k) + vColloc(i,j,k) / 2.0d0
 650          vStag(i  ,j  ,k) = vStag(i  ,j  ,k) + vColloc(i,j,k) / 2.0d0
 651        end do
 652      end do
 653    end do
 654    !$OMP END PARALLEL DO
 655
 656  end subroutine uvStagToCollocAdj
 657
 658  !--------------------------------------------------------------------------
 659  ! Symmetrize
 660  !--------------------------------------------------------------------------
 661  subroutine symmetrize(field_out, field_in, iBeg, iEnd, jBeg, jEnd, nk)
 662    !
 663    !:Purpose: Extend symmetrically outside 1 grid point all around LAM-boundary
 664    !          ready for finite differences
 665    !
 666    implicit none
 667
 668    ! Arguments:
 669    integer, intent(in) :: iBeg
 670    integer, intent(in) :: iEnd
 671    integer, intent(in) :: jBeg
 672    integer, intent(in) :: jEnd
 673    integer, intent(in) :: nk
 674    real(8), intent(out):: field_out(iBeg-1:iEnd+1,jBeg-1:jEnd+1, nk)
 675    real(8), intent(in) :: field_in(iBeg:iEnd,jBeg:jEnd,nk)
 676
 677    ! Locals:
 678    real(8), allocatable :: field_8(:,:,:)
 679
 680    integer :: ni,nj
 681
 682    ni = iEnd-iBeg+1
 683    nj = jEnd-jBeg+1
 684
 685    allocate(field_8(0:ni+1,0:nj+1, nk))
 686    field_8(:,:,:) = 0.d0
 687
 688    field_8(1:ni,1:nj,:) = field_in(iBeg:iEnd,jBeg:jEnd,:)
 689
 690    call RPN_COMM_xch_halo_8(field_8,                & ! INOUT
 691                             0,ni+1,0,nj+1,ni,nj,nk, & ! IN
 692                             1,1,.true.,.true.,ni,0)   ! IN
 693
 694    field_out(iBeg-1:iEnd+1,jBeg-1:jEnd+1,:) = field_8(0:ni+1,0:nj+1,:)
 695    deallocate(field_8)
 696
 697  end subroutine symmetrize
 698
 699  !--------------------------------------------------------------------------
 700  ! SymmetrizeAdj
 701  !--------------------------------------------------------------------------
 702  subroutine symmetrizeAdj(field_in, field_out, iBeg, iEnd, jBeg, jEnd, nk)
 703    !
 704    !:Purpose: Adjoint of sub. symmetrize.
 705    !
 706    implicit none
 707
 708    ! Arguments:
 709    integer, intent(in)  :: iBeg
 710    integer, intent(in)  :: iEnd
 711    integer, intent(in)  :: jBeg
 712    integer, intent(in)  :: jEnd
 713    integer, intent(in)  :: nk
 714    real(8), intent(in)  :: field_in(iBeg-1:iEnd+1,jBeg-1:jEnd+1, nk)
 715    real(8), intent(out) :: field_out(iBeg:iEnd,jBeg:jEnd,nk)
 716
 717    ! Locals:
 718    real(8), allocatable :: field_8(:,:,:)
 719    integer :: i,j,k,ni,nj
 720
 721    ni = iEnd-iBeg+1
 722    nj = jEnd-jBeg+1
 723
 724    allocate(field_8(0:ni+1,0:nj+1, nk))
 725    field_8(0:ni+1,0:nj+1,:) = field_in(iBeg-1:iEnd+1,jBeg-1:jEnd+1,:)
 726
 727    call RPN_COMM_adj_halo8(field_8,                 & ! INOUT
 728                            0,ni+1,0,nj+1,ni,nj,nk,  & ! IN
 729                            1,1,.true.,.true.,ni,0)    ! IN
 730
 731    !$OMP PARALLEL DO PRIVATE (k,j,i)
 732    do k = 1, nk
 733       do j = jBeg, jEnd
 734          do i = iBeg, iEnd
 735             field_out(i,j,k) = field_out(i,j,k) + field_8(i-iBeg+1,j-jBeg+1,k)
 736          end do
 737       end do
 738    end do
 739    !$OMP END PARALLEL DO
 740
 741    deallocate(field_8)
 742
 743  end subroutine symmetrizeAdj
 744
 745  !--------------------------------------------------------------------------
 746  ! lgt_Mach
 747  !--------------------------------------------------------------------------
 748  subroutine lgt_mach(gd,ni,nj,nk)
 749    !
 750    !:Purpose:  [to be completed]
 751    !
 752    !:Arguments:
 753    !       :ni: Maximum I-dimension where the input array is assumed to carry
 754    !            information.  Will be used as I-limit where backward
 755    !            derivatives will be evaluated
 756    !
 757    !       :nj: Maximum J-dimension where the input array is assumed to carry
 758    !            information. Will be used as J-limit where backward derivatives
 759    !            will be evaluated
 760    !
 761    implicit none
 762
 763    ! Arguments:
 764    integer, intent(in)    :: ni
 765    integer, intent(in)    :: nj
 766    integer, intent(in)    :: nk
 767    real(8), intent(inout) :: gd(ni,nj,nk)
 768
 769    ! Locals:
 770    integer :: istart, jstart
 771    integer :: i,j,k
 772    real(8) :: con, xp, yp, a0, a1, b1, b2
 773    real(8) :: deriv_istart, deriv_jstart, deriv_i0, deriv_j0, del
 774
 775    if ( hco_ext%global ) then
 776      call utl_abort('lgt_Mach: Not compatible with global grid')
 777    endif
 778
 779    if ( .not. initialized ) then
 780      call utl_abort('lgt_Mach: AnalysisGrid not initialized')
 781    endif
 782
 783    if ( (ni /= 1 .and. ni /= ni_ext) .or. &
 784         (nj /= 1 .and. nj /= nj_ext) ) then
 785      call utl_abort('lgt_Mach: Invalid Dimensions')
 786    end if
 787
 788    !$OMP PARALLEL
 789    !$OMP DO PRIVATE (k,j,i,istart,jstart,con,a0,a1,b1,b2,del,deriv_istart,deriv_i0,deriv_jstart,deriv_j0,xp,yp)
 790    do k = 1, nk
 791    !
 792    !- 1.  Periodicized in x-direction from ni_core to ni
 793    !    
 794    if ( ni > 1 ) then
 795      istart = ni_core - 2  ! I-limit where backward derivatives will be evaluated
 796      con = 1.d0 / ( glmf%rdlon * MPC_DEGREES_PER_RADIAN_R8 * 111.d+3)
 797      do j = 1, nj
 798        a0           = 0.5d0 * ( gd(istart,j,k)  + gd(1,j,k)       )
 799        a1           = 0.5d0 * ( gd(istart,j,k)  - gd(1,j,k)       )
 800        deriv_istart = con   * ( gd(istart,j,k)  - gd(istart-1,j,k))
 801        deriv_i0     = con   * ( gd(2,j,k)       - gd(1,j,k)       )
 802        b1           = 0.5d0 * ( deriv_istart  - deriv_i0       )
 803        b2           = 0.25d0* ( deriv_istart  + deriv_i0       )
 804        del          = real(ni_ext_per-istart,8)
 805        do i = istart, ni
 806          xp = MPC_PI_R8 * real(i-istart,8) / del
 807          gd(i,j,k) = a0 + a1*cos(xp) + b1*sin(xp) + b2*sin(2.d0*xp)
 808        end do
 809      end do
 810    end if
 811    !
 812    !- 2.  Periodicized in y-direction from nj_core to nj
 813    !
 814    if ( nj > 1 ) then
 815      jstart = nj_core - 2
 816      con = 1.d0 / (glmf%rdlat * MPC_DEGREES_PER_RADIAN_R8 * 111.d+3)
 817      do i = 1, ni
 818        a0           = 0.5d0 * ( gd(i,jstart,k) + gd(i,1,k)       )
 819        a1           = 0.5d0 * ( gd(i,jstart,k) - gd(i,1,k)       )
 820        deriv_jstart = con   * ( gd(i,jstart,k) - gd(i,jstart-1,k))
 821        deriv_j0     = con   * ( gd(i,2,k)      - gd(i,1,k)       )
 822        b1           = 0.5d0 * ( deriv_jstart - deriv_j0     )
 823        b2           = 0.25d0* ( deriv_jstart + deriv_j0     )
 824        del          = real(nj_ext_per-jstart,8)
 825        do j = jstart , nj
 826          yp = MPC_PI_R8 * real(j-jstart,8) / del
 827          gd(i,j,k) = a0 + a1*cos(yp) + b1*sin(yp) + b2*sin(2.d0*yp)
 828        end do
 829      end do
 830    end if
 831
 832    end do
 833    !$OMP END DO
 834    !$OMP END PARALLEL
 835
 836  end subroutine lgt_mach
 837
 838  !--------------------------------------------------------------------------
 839  ! lgt_Mach_r4
 840  !--------------------------------------------------------------------------
 841  subroutine lgt_mach_r4(gd,ni,nj,nk)
 842    !:Purpose:  [to be completed]
 843    !
 844    !:Arguments:
 845    !       :ni:  Maximum I-dimension where the input array is assumed to carry
 846    !             information. Will be used as I-limit where backward
 847    !             derivatives will be evaluated
 848    !       :nj:  Maximum J-dimension where the input array is assumed to carry
 849    !             information. Will be used as J-limit where backward
 850    !             derivatives will be evaluated
 851    !
 852    implicit none
 853
 854    ! Arguments:
 855    integer, intent(in)    :: ni
 856    integer, intent(in)    :: nj
 857    integer, intent(in)    :: nk
 858    real(4), intent(inout) :: gd(ni,nj,nk)
 859
 860    ! Locals:
 861    integer :: istart, jstart
 862    integer :: i,j,k
 863    real(4) :: con, xp, yp, a0, a1, b1, b2
 864    real(4) :: deriv_istart, deriv_jstart, deriv_i0, deriv_j0, del
 865
 866    if ( hco_ext%global ) then
 867      call utl_abort('lgt_Mach_r4: Not compatible with global grid')
 868    endif
 869
 870    if ( .not. initialized ) then
 871      call utl_abort('lgt_Mach_r4: AnalysisGrid not initialized')
 872    endif
 873
 874    if ( (ni /= 1 .and. ni /= ni_ext) .or. &
 875         (nj /= 1 .and. nj /= nj_ext) ) then
 876      call utl_abort('lgt_Mach_r4 : Invalid Dimensions')
 877    end if
 878
 879    !$OMP PARALLEL
 880    !$OMP DO PRIVATE (k,j,i,istart,jstart,con,a0,a1,b1,b2,del,deriv_istart,deriv_i0,deriv_jstart,deriv_j0,xp,yp)
 881    do k = 1, nk
 882    !
 883    !- 1.  Periodicized in x-direction from ni_core to ni
 884    !    
 885    if ( ni > 1 ) then
 886      istart = ni_core - 2  ! I-limit where backward derivatives will be evaluated
 887      con = 1.0 / ( glmf%rdlon * MPC_DEGREES_PER_RADIAN_R4 * 111.e+3)
 888      do j = 1, nj
 889        a0           = 0.50 * ( gd(istart,j,k)  + gd(1,j,k)       )
 890        a1           = 0.50 * ( gd(istart,j,k)  - gd(1,j,k)       )
 891        deriv_istart = con   * ( gd(istart,j,k)  - gd(istart-1,j,k))
 892        deriv_i0     = con   * ( gd(2,j,k)       - gd(1,j,k)       )
 893        b1           = 0.50 * ( deriv_istart  - deriv_i0       )
 894        b2           = 0.250* ( deriv_istart  + deriv_i0       )
 895        del          = real(ni_ext_per-istart,8)
 896        do i = istart, ni
 897          xp = MPC_PI_R4 * real(i-istart,8) / del
 898          gd(i,j,k) = a0 + a1*cos(xp) + b1*sin(xp) + b2*sin(2.0*xp)
 899        end do
 900      end do
 901    end if
 902    !
 903    !- 2.  Periodicized in y-direction from nj_core to nj
 904    !
 905    if ( nj > 1 ) then
 906      jstart = nj_core - 2
 907      con = 1.0 / (glmf%rdlat * MPC_DEGREES_PER_RADIAN_R4 * 111.e+3)
 908      do i = 1, ni
 909        a0           = 0.50 * ( gd(i,jstart,k) + gd(i,1,k)       )
 910        a1           = 0.50 * ( gd(i,jstart,k) - gd(i,1,k)       )
 911        deriv_jstart = con   * ( gd(i,jstart,k) - gd(i,jstart-1,k))
 912        deriv_j0     = con   * ( gd(i,2,k)      - gd(i,1,k)       )
 913        b1           = 0.50 * ( deriv_jstart - deriv_j0     )
 914        b2           = 0.250* ( deriv_jstart + deriv_j0     )
 915        del          = real(nj_ext_per-jstart,8)
 916        do j = jstart , nj
 917          yp = MPC_PI_R4 * real(j-jstart,8) / del
 918          gd(i,j,k) = a0 + a1*cos(yp) + b1*sin(yp) + b2*sin(2.0*yp)
 919        end do
 920      end do
 921    end if
 922
 923    end do
 924    !$OMP END DO
 925    !$OMP END PARALLEL
 926
 927  end subroutine lgt_mach_r4
 928
 929  !--------------------------------------------------------------------------
 930  ! lgt_UVToVortDiv
 931  !--------------------------------------------------------------------------
 932  subroutine lgt_UVToVortDiv(Vorticity, Divergence, uphy, vphy, nk)
 933    implicit none
 934
 935    ! Arguments:
 936    integer, intent(in)  :: nk
 937    real(8), intent(out)  :: Vorticity (myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 938    real(8), intent(out)  :: Divergence(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 939    real(8), intent(in) :: uphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 940    real(8), intent(in) :: vphy(myLonBeg:myLonEnd,myLatBeg:myLatEnd,nk)
 941
 942    ! Locals:
 943    real(8), allocatable :: uimg(:,:,:)
 944    real(8), allocatable :: vimg(:,:,:)
 945    real(8), allocatable :: uimg_sym(:,:,:)
 946    real(8), allocatable :: vimg_sym(:,:,:)
 947    integer :: i,j,k
 948
 949    if ( hco_ext%global ) then
 950      call utl_abort('lgt_UVToVortDiv: Not compatible with global grid')
 951    endif
 952
 953    if ( .not. initialized ) then
 954      call utl_abort('lgt_UVToVortDiv: AnalysisGrid not initialized')
 955    endif
 956
 957    allocate(uimg_sym( (myLonBeg-1):(myLonEnd+1), (myLatBeg-1):(myLatEnd+1), nk))
 958    allocate(vimg_sym( (myLonBeg-1):(myLonEnd+1), (myLatBeg-1):(myLatEnd+1), nk))
 959    allocate(uimg    ( myLonBeg:myLonEnd        , myLatBeg:myLatEnd        , nk))
 960    allocate(vimg    ( myLonBeg:myLonEnd        , myLatBeg:myLatEnd        , nk))
 961
 962    !
 963    !- 2.  Convert Physical (true) winds to Wind images
 964    !
 965    !$OMP PARALLEL DO PRIVATE (j)
 966    do j = myLatBeg, myLatEnd
 967          uimg(:,j,:) =  glmf%conima(j) * uphy(:,j,:)
 968          vimg(:,j,:) =  glmf%conima(j) * vphy(:,j,:)
 969    end do
 970    !$OMP END PARALLEL DO
 971
 972    !
 973    !- 3.  Symmetrize
 974    !
 975    call symmetrize( uimg_sym,                                        & ! OUT
 976                     uimg, myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 977    call symmetrize( vimg_sym,                                        & ! OUT
 978                     vimg, myLonBeg, myLonEnd, myLatBeg, myLatEnd, nk ) ! IN
 979    deallocate(uimg,vimg)
 980
 981    !
 982    !- 4.  Compute Vorticity and Divergence
 983    !
 984
 985    !$OMP PARALLEL DO PRIVATE (k,j,i)
 986     do k = 1, nk
 987       do j = myLatBeg, myLatEnd
 988         do i = myLonBeg, myLonEnd
 989           vorticity (i,j,k) = &
 990                glmf%cos2hvd(j) * glmf%dx       * (vimg_sym(i+1,j,k)-vimg_sym(i,j,k)) - &
 991                       ec_r1sa  * glmf%idmu(j)  * (uimg_sym(i,j+1,k)-uimg_sym(i,j,k))
 992
 993           divergence(i,j,k) = &
 994                glmf%cos2vd(j) * glmf%dx        * (uimg_sym(i,j,k)-uimg_sym(i-1,j,k)) + &
 995                       ec_r1sa * glmf%idmuh(j-1)* (vimg_sym(i,j,k)-vimg_sym(i,j-1,k))
 996         end do
 997       end do
 998     end do
 999     !$OMP END PARALLEL DO
1000
1001    deallocate(uimg_sym)
1002    deallocate(vimg_sym)
1003
1004  end subroutine lgt_UVToVortDiv
1005
1006  !--------------------------------------------------------------------------
1007  ! lgt_createLamTemplateGrids
1008  !--------------------------------------------------------------------------
1009  subroutine lgt_createLamTemplateGrids(templateFileName, hco_core, vco, &
1010                                        grd_ext_x, grd_ext_y)
1011    implicit none
1012
1013    ! Arguments:
1014    character(len=*), intent(in) :: templateFileName
1015    type(struct_hco), intent(in) :: hco_core
1016    type(struct_vco), intent(in) :: vco
1017    integer         , intent(in) :: grd_ext_x
1018    integer         , intent(in) :: grd_ext_y
1019
1020    ! Locals:
1021    integer :: ni_ext, nj_ext, i, j, lev, ni, nj, nk
1022    integer :: iun = 0
1023    integer :: ier, fnom, fstouv, fstfrm, fclos, fstecr
1024    real(8), allocatable :: Field2d(:,:)
1025    real(8), allocatable :: lat_ext(:)
1026    real(8), allocatable :: lon_ext(:)
1027    real(4), allocatable :: dummy2D(:,:)
1028    real(8) :: dlat, dlon
1029    real(4) :: work
1030    integer :: dateo,npak,status
1031    integer :: ip1,ip2,ip3,deet,npas,datyp,ig1,ig2,ig3,ig4
1032    integer :: ig1_tictac,ig2_tictac,ig3_tictac,ig4_tictac
1033    character(len=1)  :: grtyp
1034    character(len=2)  :: typvar
1035    character(len=12) :: etiket
1036
1037    !
1038    !- 1.  Opening the output template file
1039    !
1040    ier = fnom(iun, trim(templateFileName), 'RND', 0)
1041    ier = fstouv(iun, 'RND')
1042
1043    npak     = -32
1044
1045    !
1046    !- 2.  Writing the core grid (Ensemble) template
1047    !
1048
1049    !- 2.1 Tic-Tac
1050    deet     =  0
1051    ip1      =  hco_core%ig1
1052    ip2      =  hco_core%ig2
1053    ip3      =  hco_core%ig3
1054    npas     =  0
1055    datyp    =  1
1056    grtyp    =  hco_core%grtypTicTac
1057    typvar   = 'X'
1058    etiket   = 'COREGRID'
1059    dateo =  0
1060
1061    call cxgaig ( grtyp,                                          & ! IN
1062         ig1_tictac, ig2_tictac, ig3_tictac, ig4_tictac, & ! OUT
1063         real(hco_core%xlat1), real(hco_core%xlon1),   & ! IN
1064         real(hco_core%xlat2), real(hco_core%xlon2)  )   ! IN
1065
1066    ig1      =  ig1_tictac
1067    ig2      =  ig2_tictac
1068    ig3      =  ig3_tictac
1069    ig4      =  ig4_tictac
1070
1071    ier = utl_fstecr(hco_core%lon*MPC_DEGREES_PER_RADIAN_R8, npak, &
1072         iun, dateo, deet, npas, hco_core%ni, 1, 1, ip1,    &
1073         ip2, ip3, typvar, '>>', etiket, grtyp, ig1,          &
1074         ig2, ig3, ig4, datyp, .true.)
1075
1076    ier = utl_fstecr(hco_core%lat*MPC_DEGREES_PER_RADIAN_R8, npak, &
1077         iun, dateo, deet, npas, 1, hco_core%nj, 1, ip1,    &
1078         ip2, ip3, typvar, '^^', etiket, grtyp, ig1,          &
1079         ig2, ig3, ig4, datyp, .true.)
1080
1081    !- 2.2 2D Field
1082    allocate(Field2d(hco_core%ni,hco_core%nj))
1083    Field2d(:,:) = 10.d0
1084
1085    deet      =  0
1086    ip1       =  0
1087    ip2       =  0
1088    ip3       =  0
1089    npas      =  0
1090    datyp     =  1
1091    grtyp     =  hco_core%grtyp
1092    typvar    = 'A'
1093    etiket    = 'COREGRID'
1094    dateo     =  0
1095    ig1       =  hco_core%ig1
1096    ig2       =  hco_core%ig2
1097    ig3       =  hco_core%ig3
1098    ig4       =  hco_core%ig4
1099
1100    ier = utl_fstecr(Field2d, npak,                                    &
1101         iun, dateo, deet, npas, hco_core%ni, hco_core%nj, 1, ip1, &
1102         ip2, ip3, typvar, 'P0', etiket, grtyp, ig1,                &
1103         ig2, ig3, ig4, datyp, .true.)
1104
1105    deallocate(Field2d)
1106
1107    !
1108    !- 3.  Create and Write the extended grid (Analysis) template
1109    !
1110    ni_ext = hco_core%ni + grd_ext_x
1111    nj_ext = hco_core%nj + grd_ext_y
1112
1113    !- 3.1 Tic-Tac
1114    allocate(lon_ext(ni_ext))
1115    allocate(lat_ext(nj_ext))
1116
1117    !- Copy core grid info
1118    lon_ext(1:hco_core%ni) = hco_core%lon(:) 
1119    lat_ext(1:hco_core%nj) = hco_core%lat(:)
1120
1121    !- Extend the lat lon
1122    dlon = hco_core%lon(2) - hco_core%lon(1) 
1123    do i = hco_core%ni + 1, ni_ext
1124      lon_ext(i) = lon_ext(hco_core%ni) + (i - hco_core%ni) * dlon
1125    end do
1126
1127    dlat = hco_core%lat(2) - hco_core%lat(1) 
1128    do j = hco_core%nj + 1, nj_ext
1129      lat_ext(j) = lat_ext(hco_core%nj) + (j - hco_core%nj) * dlat
1130    end do
1131
1132    !- Write
1133    deet     =  0
1134    ip1      =  hco_core%ig1 + 100 ! Must be different from the core grid
1135    ip2      =  hco_core%ig2 + 100 ! Must be different from the core grid
1136    if (hco_core%ig3 > 0) then
1137      ip3      =  hco_core%ig3 + 100 ! Must be different from the core grid
1138    else
1139      ip3      =  0
1140    end if
1141    npas     =  0
1142    datyp    =  1
1143    grtyp    =  hco_core%grtypTicTac
1144    typvar   = 'X'
1145    etiket   = 'ANALYSIS'
1146    dateo    =  0
1147    ig1      =  ig1_tictac
1148    ig2      =  ig2_tictac
1149    ig3      =  ig3_tictac
1150    ig4      =  ig4_tictac
1151
1152    ier = utl_fstecr(lon_ext*MPC_DEGREES_PER_RADIAN_R8, npak, &
1153         iun, dateo, deet, npas, ni_ext, 1, 1, ip1,  &
1154         ip2, ip3, typvar, '>>', etiket, grtyp, ig1,    &
1155         ig2, ig3, ig4, datyp, .true.)
1156
1157    ier = utl_fstecr(lat_ext*MPC_DEGREES_PER_RADIAN_R8, npak, &
1158         iun, dateo, deet, npas, 1, nj_ext, 1, ip1,  &
1159         ip2, ip3, typvar, '^^', etiket, grtyp, ig1,    &
1160         ig2, ig3, ig4, datyp, .true.)
1161
1162    deallocate(lon_ext)
1163    deallocate(lat_ext)
1164
1165    !- 3.2 2D Field
1166    allocate(Field2d(ni_ext,nj_ext))
1167    Field2d(:,:) = 10.d0
1168
1169    deet      =  0
1170    ip1       =  0
1171    ip2       =  0
1172    ip3       =  0
1173    npas      =  0
1174    datyp     =  1
1175    grtyp     =  hco_core%grtyp
1176    typvar    = 'A'
1177    etiket    = 'ANALYSIS'
1178    dateo     =  0
1179    ig1       =  hco_core%ig1 + 100 ! Must be different from the core grid
1180    ig2       =  hco_core%ig2 + 100 ! Must be different from the core grid
1181    if (hco_core%ig3 > 0) then
1182      ig3      =  hco_core%ig3 + 100 ! Must be different from the core grid
1183    else
1184      ig3      =  0
1185    end if
1186    ig4       =  0
1187
1188    ier = utl_fstecr(Field2d, npak,                                  &
1189         iun, dateo, deet, npas, ni_ext, nj_ext, 1, ip1, &
1190         ip2, ip3, typvar, 'P0', etiket, grtyp, ig1,     &
1191         ig2, ig3, ig4, datyp, .true.)
1192
1193    deallocate(Field2d)
1194
1195    !
1196    !- 4. Write the vertical grid description
1197    !
1198
1199    if (vco%vgridPresent) then
1200      !- 4.1 Write the toc-toc
1201      status = vgd_write(vco%vgrid,iun,'fst')
1202      
1203      if ( status /= VGD_OK ) then
1204        call utl_abort('createLamTemplateGrids: ERROR with vgd_write')
1205      end if
1206      
1207      !- 4.2 Write a dummy 2D field for each MM and TH levels
1208      npak   = -12
1209      dateo  = 0
1210      deet   = 0
1211      npas   = 0
1212      ni     = 4
1213      nj     = 2
1214      nk     = 1
1215      ip2    = 0
1216      ip3    = 0
1217      typvar = 'A'
1218      etiket = 'VERTICALGRID'
1219      grtyp  = 'G'
1220      ig1    = 0
1221      ig2    = 0
1222      ig3    = 0
1223      ig4    = 0
1224      datyp  = 1
1225      
1226      allocate(dummy2D(ni,nj))
1227      dummy2D(:,:) = 0.0
1228      
1229      do lev = 1, vco%nlev_M
1230        ip1 = vco%ip1_M(lev)
1231        ier = fstecr(dummy2D, work, npak, iun, dateo, deet, npas, ni, nj, &
1232                     nk, ip1, ip2, ip3, typvar, 'MM', etiket, grtyp,              &
1233                     ig1, ig2, ig3, ig4, datyp, .true.)
1234      end do
1235      do lev = 1, vco%nlev_T
1236        ip1 = vco%ip1_T(lev)
1237        ier = fstecr(dummy2D, work, npak, iun, dateo, deet, npas, ni, nj, &
1238                     nk, ip1, ip2, ip3, typvar, 'TH', etiket, grtyp,              &
1239                     ig1, ig2, ig3, ig4, datyp, .true.)
1240      end do
1241
1242      deallocate(dummy2D)
1243    end if ! vco%vgridPresent
1244
1245    !
1246    !- 5.  Closing the output template file
1247    !
1248    ier = fstfrm(iun)
1249    ier = fclos (iun)
1250
1251  end subroutine lgt_createLamTemplateGrids
1252
1253end module lamAnalysisGridTransforms_mod