verticalCoord_mod sourceΒΆ

   1module verticalCoord_mod
   2  ! MODULE verticalCoord_mod (prefix='vco' category='7. Low-level data objects')
   3  !
   4  !:Purpose:  Derived type and procedures related to the vertical levels.
   5  !           The derived type includes a pointer to the associated VGRID
   6  !           descriptor.
   7  !
   8  use midasMpi_mod
   9  use Vgrid_Descriptors
  10  use varNameList_mod
  11  use utilities_mod
  12  
  13  implicit none
  14  
  15  private
  16
  17  ! public derived type
  18  public :: struct_vco
  19  ! public variables
  20  public :: vco_ip1_other, vco_maxNumLevels
  21  ! public procedures
  22  public :: vco_setupFromFile, vco_getNumLev, vco_equal, vco_deallocate, vco_mpiBcast
  23  public :: vco_subsetOrNot, vco_levelMatchingList
  24
  25  integer, parameter :: maxNumOtherLevels = 20
  26  integer :: vco_ip1_other(maxNumOtherLevels)
  27
  28  integer, parameter :: vco_maxNumLevels = 200
  29  
  30  type struct_vco
  31     logical :: initialized=.false.
  32     integer :: Vcode = -1
  33     integer :: nlev_T = 0
  34     integer :: nlev_M = 0
  35     integer :: nlev_Other(vnl_numvarmaxOther) = 0
  36     integer :: nlev_Depth = 0
  37     integer :: ip1_seaLevel
  38     integer :: ip1_sfc   ! ip1 value for the surface (hybrid = 1)
  39     integer :: ip1_T_2m  ! ip1 value for the 2m thermodynamic level
  40     integer :: ip1_M_10m ! ip1 value for the 10m momentum level
  41     integer, pointer :: ip1_T(:) => null()
  42     integer, pointer :: ip1_M(:) => null()  ! encoded IP1 levels (Thermo/Moment)
  43     integer, pointer :: ip1_depth(:) => null() ! encoded IP1 levels (Ocean depth levels)
  44     type(vgrid_descriptor) :: vgrid
  45     logical :: vgridPresent
  46     real(8), pointer :: depths(:) => null()
  47  end type struct_vco
  48
  49contains
  50  
  51  !--------------------------------------------------------------------------
  52  ! vco_allocateIp1
  53  !--------------------------------------------------------------------------
  54  subroutine vco_allocateIp1(vco)
  55    !
  56    !:Purpose: Allocate the ip1 arrays of a vertical coordinate object.
  57    !
  58    implicit none
  59
  60    ! Arguments:
  61    type(struct_vco), pointer, intent(inout) :: vco ! Vertical coordinate object
  62
  63    ! Locals:
  64    integer :: numLev
  65
  66    numLev = vco_getNumLev(vco,'MM')
  67    if (numLev > 0) allocate (vco%ip1_M(numLev))
  68
  69    numLev = vco_getNumLev(vco,'TH')
  70    if (numLev > 0) allocate (vco%ip1_T(numLev))
  71
  72  end subroutine vco_allocateIp1
  73
  74  !--------------------------------------------------------------------------
  75  ! vco_SetupFromFile
  76  !--------------------------------------------------------------------------
  77  subroutine vco_SetupFromFile(vco, templatefile, etiket_opt, beSilent_opt)
  78    ! 
  79    !:Purpose: Initialize vertical coordinate object with information from 
  80    !           a standard file.
  81    !
  82    implicit none
  83
  84    ! Arguments:
  85    type(struct_vco),pointer,   intent(inout) :: vco          ! Vertical coordinate object 
  86    character(len=*),           intent(in)    :: templatefile ! Template file
  87    character(len=*), optional, intent(in)    :: etiket_opt   ! Optional argument etiket
  88    logical,          optional, intent(in)    :: beSilent_opt ! Optional argument beSilent
  89
  90    ! Locals:
  91    logical           :: beSilent
  92    character(len=12) :: etiket
  93    integer :: nultemplate,ierr
  94    integer, parameter :: maxNumRecords = 1000
  95    integer :: recordIndex, numRecords, ikeys(maxNumRecords)
  96    integer :: fnom,fstouv,fstfrm,fclos,fstprm,fstinl
  97    integer :: ip1_sfc
  98    character(len=10) :: blk_S
  99    logical :: fileExists, atmFieldFound, sfcFieldFound, oceanFieldFound
 100    integer :: IP1kind
 101    real :: vertCoordValue
 102    integer :: ideet, inpas, dateStamp_origin, ini, inj, ink, inbits, idatyp
 103    integer :: ip1, ip2, ip3, ig1, ig2, ig3, ig4, iswa, ilng, idltf, iubc
 104    integer :: iextra1, iextra2, iextra3
 105    character(len=2)  :: typvar
 106    character(len=4)  :: nomvar
 107    character(len=1)  :: grtyp
 108
 109    if ( associated(vco) ) then
 110      call utl_abort('vco_setupFromFile: the supplied vco pointer is not null!')
 111    end if
 112
 113    allocate(vco)
 114    call convip(vco%ip1_seaLevel, 0.0, 0, 2, blk_s, .false.) 
 115
 116    if (present(etiket_opt)) then
 117      etiket = etiket_opt
 118    else
 119      etiket = ' '
 120    end if
 121
 122    if (present(beSilent_opt)) then
 123      beSilent = beSilent_opt
 124    else
 125      beSilent = .false.
 126    end if
 127
 128    ! Check if template file exists
 129    if (mmpi_myid == 0 .and. .not. beSilent) then
 130      write(*,*) 'vco_setupFromFile: Template File = ', trim(templatefile)
 131    end if
 132    inquire(file=templatefile,exist=fileExists)
 133    if ( .not. fileExists )then
 134      write(*,*) 'vco_setupFromFile: Template File = ', trim(templatefile)
 135      call utl_abort('vco_setupFromFile: CANNOT FIND TEMPLATE FILE!')
 136    end if
 137
 138    ! First priority, check if vgrid descriptor record present - if so, atmospheric fields
 139    atmFieldFound = utl_varNamePresentInFile('!!',fileName_opt=trim(templatefile))
 140
 141    ! If not atmospheric field, we need to examine data records in the template file
 142    if (.not. atmFieldFound) then
 143
 144      if (.not. beSilent) then
 145        write(*,*) 'vco_setupFromFile: No vgrid descriptor found, examine data records in template file'
 146      end if
 147
 148      ! open the template file
 149      nultemplate=0
 150      ierr=fnom(nultemplate,templatefile,'RND+OLD+R/O',0)
 151      if ( ierr == 0 ) then
 152        ierr =  fstouv(nultemplate,'RND+OLD')
 153      else
 154        write(*,*) 'vco_setupFromFile: Template File = ', trim(templatefile)
 155        call utl_abort('vco_setupFromFile: CANNOT OPEN TEMPLATE FILE!')
 156      end if
 157
 158      ierr = fstinl(nultemplate,ini,inj,ink,-1,etiket,-1,-1,-1,' ', &
 159                    ' ',ikeys,numRecords,maxNumRecords)
 160      if (ikeys(1) <= 0) then
 161        call utl_abort('vco_setupFromFile: Could not find any records in the supplied file')
 162      end if
 163      if (.not. beSilent) then
 164        write(*,*) 'vco_setupFromFile: number of records found = ', numRecords
 165      end if
 166
 167      ! check records for ocean or surface fields
 168      sfcFieldFound   = .false.
 169      oceanFieldFound = .false.
 170      record_loop: do recordIndex = 1, numRecords
 171        ierr = fstprm(ikeys(recordIndex), dateStamp_origin, ideet, inpas, ini, inj, &
 172                      ink, inbits, idatyp, ip1, ip2, ip3, &
 173                      typvar, nomvar, etiket, grtyp, ig1, ig2, ig3, ig4, &
 174                      iswa, ilng, idltf, iubc, iextra1, iextra2, iextra3)
 175
 176        ! ignore any variables not present in varnamelist_mod
 177        if (.not. vnl_varnameIsValid(trim(nomvar))) cycle record_loop
 178
 179        ! check for record with ocean data
 180        call convip(ip1, vertCoordValue, Ip1Kind, -1, blk_s, .false.) 
 181        if (Ip1Kind == 0 .and. &
 182            vnl_varKindFromVarname(trim(nomvar)) == 'OC') then
 183          oceanFieldFound = .true.
 184          exit record_loop
 185        end if
 186
 187        ! check for record with surface data (and that are not ocean variables)
 188        call convip(ip1_sfc, 1.0, 5, 2, blk_s, .false.) 
 189        if (ip1 == 0 .or. ip1 == ip1_sfc .or. ip1 == vco%ip1_seaLevel .or. Ip1Kind == 3) then
 190          sfcFieldFound = .true.
 191          exit record_loop
 192        end if
 193
 194        ! something else was found, abort (not sure abort is necessary)
 195        write(*,*) 'vco_setupFromFile: found record with unknown vertical coordinate'
 196        write(*,*) 'varName = ', trim(nomvar), ' typvar = ', typvar, ' ip1 = ', ip1
 197        call utl_abort('vco_setupFromFile: found a non-surface field')
 198
 199      end do record_loop
 200
 201      ierr =  fstfrm(nultemplate)
 202      ierr =  fclos (nultemplate)
 203
 204    end if
 205
 206    ! call appropriate setup routine based on what was found in template file
 207    if (atmFieldFound) then
 208      call vco_setupAtmFromFile(vco, templatefile, etiket, beSilent)
 209    else if (oceanFieldFound) then
 210      call vco_setupOceanFromFile(vco, templatefile, etiket, beSilent)
 211    else if (sfcFieldFound) then
 212      call vco_setupSfcFromFile(vco, beSilent)
 213    else
 214      call utl_abort('vco_setupFromFile: could not setup vco from template file')
 215    end if
 216
 217  end subroutine vco_setupFromFile
 218
 219  !--------------------------------------------------------------------------
 220  ! vco_setupAtmFromFile
 221  !--------------------------------------------------------------------------
 222  subroutine vco_setupAtmFromFile(vco, templatefile, etiket, beSilent)
 223    ! 
 224    !:Purpose: Initialize vertical coordinate object with information from 
 225    !           a standard file. Use vgrid descriptor for atmospheric fields.
 226    !
 227    implicit none
 228
 229    ! Arguments:
 230    type(struct_vco), pointer, intent(inout) :: vco          ! Vertical coordinate object 
 231    character(len=*),          intent(in)    :: templatefile ! Template file
 232    character(len=*),          intent(in)    :: etiket
 233    logical,                   intent(in)    :: beSilent
 234
 235    ! Locals:
 236    integer :: Vcode, jlev, nlevMatched, stat, nultemplate, ierr, ikey
 237    integer :: fnom, fstouv, fstfrm, fclos, fstinf
 238    integer :: vgd_nlev_M, vgd_nlev_T, ip1_sfc
 239    integer :: ni, nj, nk, varListIndex, IP1kind
 240    integer,   pointer :: vgd_ip1_M(:), vgd_ip1_T(:)
 241    logical :: ip1_found
 242    character(len=10) :: blk_S
 243    character(len=4) :: nomvar_T, nomvar_M, nomvar_Other
 244    character(len=10) :: IP1string
 245    real :: otherVertCoordValue
 246
 247    ! Open the template file
 248    nultemplate = 0
 249    ierr = fnom(nultemplate,templatefile,'RND+OLD+R/O',0)
 250    if (ierr == 0) then
 251      ierr = fstouv(nultemplate,'RND+OLD')
 252    else
 253      write(*,*) 'vco_setupFromFile: Template File = ', trim(templatefile)
 254      call utl_abort('vco_setupAtmFromFile: CANNOT OPEN TEMPLATE FILE!')
 255    end if
 256
 257    ! Try creating vgrid descriptor
 258    stat = vgd_new(vco%vgrid, unit = nultemplate, format = "fst", ip1 = -1, ip2 = -1)
 259    if (stat == VGD_OK) then
 260      vco%vgridPresent = .true.
 261    else
 262      call utl_abort('vco_setupAtmFromFile: !! record exists, but not able to create descriptor object')
 263    end if
 264
 265    ! Print out vertical structure 
 266    if (mmpi_myid == 0 .and. .not. beSilent) then
 267      call flush(6) ! possibly needed so vgd_print output appears correctly in listing
 268      stat = vgd_print(vco%vgrid)
 269      if (stat /= VGD_OK)then
 270        call utl_abort('vco_setupAtmFromFile: ERROR with vgd_print')
 271      end if
 272    end if
 273
 274    ! Get version of the vertical coordinate
 275    stat = vgd_get(vco%vgrid, key = 'ig_1 - vertical coord code', value = Vcode)
 276    if ( stat /= VGD_OK ) then
 277      call utl_abort('vco_setupAtmFromFile: problem with vgd_get: key= ig_1 - vertical coord code')
 278    end if
 279    if (Vcode /= 5002 .and. Vcode /= 5005 .and. Vcode /= 5100 .and. Vcode /= 21001) then
 280      call utl_abort('vco_setupAtmFromFile: Invalid Vcode. Currently only 5002, 5005, 5100 and 21001 supported.')
 281    end if
 282    vco%Vcode = Vcode
 283
 284    ! Get vgrid values for ip1
 285    stat = vgd_get(vco%vgrid, key='vipm - vertical levels (m)', value = vgd_ip1_m)
 286    stat = vgd_get(vco%vgrid, key='vipt - vertical ip1 levels (t)', value = vgd_ip1_t)
 287
 288    vgd_nlev_M = size(vgd_ip1_M)
 289    vgd_nlev_T = size(vgd_ip1_T)
 290
 291    ! Set the number of vertical levels and allocate vco arrays
 292    vco%nlev_T = 0
 293    nomvar_T = 'TH  '
 294    do jlev = 1, vgd_nlev_T
 295      ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_T(jlev), -1, -1, ' ', nomvar_T)
 296      if (ikey > 0) vco%nlev_T = vco%nlev_T + 1
 297    end do
 298    if (vco%nlev_T == 0) then
 299      if (mmpi_myid == 0 .and. .not. beSilent) then
 300        write(*,*) 'vco_setupAtmFromFile: TH not found looking for TT to get nlev_T'
 301      end if
 302      nomvar_T = 'TT  '
 303      do jlev = 1, vgd_nlev_T
 304        ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_T(jlev), -1, -1, ' ', nomvar_T)
 305        if (ikey > 0) vco%nlev_T = vco%nlev_T + 1
 306      end do
 307    end if
 308    if (vco%nlev_T == 0 .and. .not. beSilent) then
 309      write(*,*) 
 310      write(*,*) 'vco_setupAtmFromFile: Could not find a valid thermodynamic variable in the template file!'
 311    else if (vco%nlev_T > vco_maxNumLevels) then
 312      write(*,*)
 313      write(*,*) 'nlev_T           = ',vco%nlev_T
 314      write(*,*) 'vco_maxNumLevels = ',vco_maxNumLevels
 315      call utl_abort('vco_setupAtmFromFile: nlev_T is greater than vco_maxNumLevels!')
 316    end if
 317
 318    vco%nlev_M = 0
 319    nomvar_M = 'MM  '
 320    do jlev = 1, vgd_nlev_M
 321      ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_M(jlev), -1, -1, ' ', nomvar_M)
 322      if (ikey > 0) vco%nlev_M = vco%nlev_M + 1
 323    end do
 324    if (vco%nlev_M == 0) then
 325      if (mmpi_myid == 0 .and. .not. beSilent) then
 326        write(*,*) 'vco_setupAtmFromFile: MM not found looking for UU to get nlev_M'
 327      end if
 328      nomvar_M = 'UU  '
 329      do jlev = 1, vgd_nlev_M
 330        ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_M(jlev), -1, -1, ' ', nomvar_M)
 331        if (ikey > 0) vco%nlev_M = vco%nlev_M + 1
 332      end do
 333    end if
 334    if (vco%nlev_M == 0) then
 335      if (mmpi_myid == 0 .and. .not. beSilent) then
 336        write(*,*) 'vco_setupAtmFromFile: UU not found looking for PP to get nlev_M'
 337      end if
 338      nomvar_M = 'PP  '
 339      do jlev = 1, vgd_nlev_M
 340        ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_M(jlev), -1, -1, ' ', nomvar_M)
 341        if (ikey > 0) vco%nlev_M = vco%nlev_M + 1
 342      end do
 343    end if
 344    if (vco%nlev_M == 0 .and. .not. beSilent) then
 345      write(*,*) 
 346      write(*,*) 'vco_setupAtmFromFile: Could not find a valid momentum variable in the template file!'
 347    else if (vco%nlev_M > vco_maxNumLevels) then
 348      write(*,*)
 349      write(*,*) 'nlev_M           = ',vco%nlev_M
 350      write(*,*) 'vco_maxNumLevels = ',vco_maxNumLevels
 351      call utl_abort('vco_setupAtmFromFile: nlev_M is greater than vco_maxNumLevels!')
 352    end if
 353
 354    do jlev = 1, maxNumOtherLevels
 355      otherVertCoordValue = real(jlev)
 356      IP1kind = 3
 357      call convip_plus(vco_ip1_other(jlev), otherVertCoordValue, IP1kind, +2, IP1string, .false.)
 358    end do
 359    vco%nlev_Other(:) = 0
 360    do varListIndex = 1, vnl_numvarmaxOther
 361      nomvar_Other = vnl_varNameListOther(varListIndex)
 362      do jlev = 1, maxNumOtherLevels
 363        ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vco_ip1_other(jlev), -1, -1, ' ', nomvar_Other)
 364        if (ikey > 0) vco%nlev_Other(varListIndex) = vco%nlev_Other(varListIndex) + 1
 365      end do
 366      if (mmpi_myid == 0 .and. .not. beSilent) then
 367        if (vco%nlev_Other(varListIndex) == 0) then
 368          write(*,*) 
 369          write(*,*) 'vco_setupAtmFromFile: Found no levels in template file for OTHER type variable ', nomvar_Other
 370        else
 371          write(*,*) 'vco_setupAtmFromFile: Found ', vco%nlev_Other(varListIndex),  &
 372               ' levels in template file for OTHER type variable ', nomvar_Other
 373        end if
 374      end if
 375    end do
 376
 377    if (vco%nlev_M == 0 .and. vco%nlev_T == 0) then
 378      call utl_abort('vco_setupAtmFromFile: they were no valid momentum and thermodynamic variables in the template file!')
 379    end  if
 380
 381    if (mmpi_myid == 0 .and. .not.beSilent) then
 382      write(*,*) 'vco_setupAtmFromFile: nlev_M, nlev_T=',vco%nlev_M,vco%nlev_T
 383    end if
 384    
 385    call vco_allocateIp1(vco)
 386
 387    ! Match up ip1 values from file and vgrid for momentum levels
 388    nlevMatched = 0
 389    do jlev = 1, vgd_nlev_M
 390      ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_M(jlev), -1, -1, ' ', nomvar_M)
 391      if (ikey > 0) then
 392        nlevMatched = nlevMatched + 1
 393        if (nlevMatched > vco%nlev_M) then
 394          call utl_abort('vco_setupAtmFromFile: Problem with consistency between vgrid descriptor and template file (momentum)')
 395        end if
 396        vco%ip1_M(nlevMatched) = vgd_ip1_M(jlev)
 397      end if
 398    end do
 399    if (nlevMatched /= vco%nlev_M) then
 400      write(*,*) 'vco_setupAtmFromFile: nlevMatched = ', nlevMatched, ', nlev_M = ', vco%nlev_M
 401      call utl_abort('vco_setupAtmFromFile: Problem with consistency between vgrid descriptor and template file (momentum)')
 402    end if
 403
 404    ! Match up ip1 values from file and vgrid for thermo levels
 405    nlevMatched = 0
 406    do jlev = 1, vgd_nlev_T
 407      ikey = fstinf(nultemplate, ni, nj, nk, -1 ,etiket, vgd_ip1_T(jlev), -1, -1, ' ', nomvar_T)
 408      if (ikey > 0) then
 409        nlevMatched = nlevMatched + 1
 410        if (nlevMatched > vco%nlev_T) then
 411          call utl_abort('vco_setupAtmFromFile: Problem with consistency between vgrid descriptor and template file (thermo)')
 412        end if
 413        vco%ip1_T(nlevMatched) = vgd_ip1_T(jlev)
 414      end if
 415    end do
 416    if (nlevMatched /= vco%nlev_T) then
 417      write(*,*) 'vco_setupAtmFromFile: nlevMatched = ', nlevMatched, ', nlev_T = ', vco%nlev_T
 418      call utl_abort('vco_setupAtmFromFile: Problem with consistency between vgrid descriptor and template file (thermo)')
 419    end if
 420
 421    ! determine IP1 of sfc (hyb=1.0)
 422    if (Vcode == 5002 .or. Vcode == 5005 .or. Vcode == 5100) then
 423      call convip(ip1_sfc, 1.0, 5, 2, blk_s, .false.)
 424    else if (Vcode == 21001) then
 425      call convip(ip1_sfc, 0.0, 21, 2, blk_s, .false.)
 426    end if
 427    ip1_found = .false.
 428    do jlev = 1, vgd_nlev_T
 429      if (ip1_sfc == vgd_ip1_T(jlev)) then
 430        ip1_found = .true.
 431        vco%ip1_sfc = vgd_ip1_T(jlev)
 432      end if
 433    end do
 434    if (.not. ip1_found) then
 435      write(*,*) 'vco_setupAtmFromFile: Could not find IP1=',ip1_sfc
 436      call utl_abort('vco_setupAtmFromFile: No surface level found in Vgrid!!!')
 437    else
 438      if (mmpi_myid == 0 .and. .not. beSilent) write(*,*) 'vco_setupAtmFromFile: Set surface level IP1=', vco%ip1_sfc
 439    end if
 440
 441    ! determine IP1s of 2m and 10m levels
 442    call set_2m_10m_levels(vco)
 443
 444    vco%initialized = .true.
 445
 446    ierr =  fstfrm(nultemplate)
 447    ierr =  fclos (nultemplate)
 448
 449  end subroutine vco_setupAtmFromFile
 450
 451  !--------------------------------------------------------------------------
 452  ! vco_setupOceanFromFile
 453  !--------------------------------------------------------------------------
 454  subroutine vco_setupOceanFromFile(vco,templatefile,etiket,beSilent)
 455    ! 
 456    !:Purpose: Initialize vertical coordinate object with information from 
 457    !           a standard file. For Ocean fields on depth levels.
 458    !
 459    implicit none
 460
 461    ! Arguments:
 462    type(struct_vco), pointer, intent(inout) :: vco          ! Vertical coordinate object 
 463    character(len=*),          intent(in)    :: templatefile ! Template file
 464    character(len=*),          intent(in)    :: etiket
 465    logical,                   intent(in)    :: beSilent
 466
 467    ! Locals:
 468    integer :: nultemplate, ierr
 469    integer, parameter :: maxNumRecords = 500
 470    integer :: recordIndex, numRecords, ikeys(maxNumRecords)
 471    integer :: fnom,fstouv,fstfrm,fclos,fstprm,fstinl
 472    character(len=10) :: blk_S
 473    integer :: IP1kind
 474    real :: vertCoordValue
 475    integer, parameter :: maxNumDepthLevels = 200
 476    real(8)            :: depths(maxNumDepthLevels)
 477    integer            :: ip1_depth(maxNumDepthLevels)
 478    integer :: ideet, inpas, dateStamp_origin, ini, inj, ink, inbits, idatyp
 479    integer :: ip1, ip2, ip3, ig1, ig2, ig3, ig4, iswa, ilng, idltf, iubc
 480    integer :: iextra1, iextra2, iextra3
 481    character(len=2)  :: typvar
 482    character(len=4)  :: nomvar
 483    character(len=1)  :: grtyp
 484
 485    if (.not. beSilent) write(*,*) 'vco_setupOceanFromFile: found ocean fields'
 486
 487    ! initialize some components of vco
 488    vco%vgridPresent = .false.
 489    vco%nlev_T = 0
 490    vco%nlev_M = 0
 491    vco%Vcode  = 0
 492    vco%initialized = .true.
 493
 494    ! open the template file
 495    nultemplate = 0
 496    ierr = fnom(nultemplate,templatefile,'RND+OLD+R/O',0)
 497    if ( ierr == 0 ) then
 498      ierr =  fstouv(nultemplate,'RND+OLD')
 499    else
 500      write(*,*) 'vco_setupFromFile: Template File = ', trim(templatefile)
 501      call utl_abort('vco_setupOceanFromFile: CANNOT OPEN TEMPLATE FILE!')
 502    end if
 503
 504    ierr = fstinl(nultemplate,ini,inj,ink,-1,etiket,-1,-1,-1,' ', &
 505                  ' ',ikeys,numRecords,maxNumRecords)
 506    if ( ikeys(1) <= 0 ) then
 507      call utl_abort('vco_setupOceanFromFile: Could not find any records ' //  &
 508                     'in the supplied file')
 509    end if
 510    record_loop: do recordIndex = 1, numRecords
 511      ierr = fstprm(ikeys(recordIndex), dateStamp_origin, ideet, inpas, ini, inj, &
 512                    ink, inbits, idatyp, ip1, ip2, ip3, &
 513                    typvar, nomvar, etiket, grtyp, ig1, ig2, ig3, ig4, &
 514                    iswa, ilng, idltf, iubc, iextra1, iextra2, iextra3)
 515
 516      ! ignore any variables not present in varnamelist_mod
 517      if (.not. vnl_varnameIsValid(trim(nomvar))) cycle record_loop
 518
 519      ! check for record with ocean data on depth levels
 520      call convip(ip1, vertCoordValue, Ip1Kind, -1, blk_s, .false.) 
 521      if ( Ip1Kind == 0 .and. vertCoordValue >= 0.0 .and. &
 522           vnl_varKindFromVarname(trim(nomvar)) == 'OC' .and. &
 523           vnl_varLevelFromVarname(trim(nomvar)) == 'DP' ) then
 524        ! check if we've NOT already recorded this depth level
 525        if ( .not. any(vertCoordValue == depths(1:vco%nLev_depth)) ) then
 526          vco%nLev_depth = vco%nLev_depth + 1
 527          depths(vco%nLev_depth) = vertCoordValue
 528          ip1_depth(vco%nLev_depth) = ip1
 529          if (mmpi_myid == 0 .and. .not.beSilent) then
 530            write(*,*) 'vco_setupOceanFromFile: found ocean record: nLev_depth = ', &
 531                 vco%nLev_depth, 'varName = ', trim(nomvar), &
 532                 ', value = ', depths(vco%nLev_depth)
 533          end if
 534        end if
 535        cycle record_loop
 536      end if
 537
 538    end do record_loop
 539
 540    ierr =  fstfrm(nultemplate)
 541    ierr =  fclos (nultemplate)
 542
 543    ! Allocate object arrays and copy in depth information
 544    allocate(vco%depths(vco%nLev_depth))
 545    allocate(vco%ip1_depth(vco%nLev_depth))
 546    vco%depths(:)    = depths(1:vco%nLev_depth)
 547    vco%ip1_depth(:) = ip1_depth(1:vco%nLev_depth)
 548
 549    ! Check if ocean depth levels are in correct order (ascending in value)
 550    if ( vco%nLev_depth > 1 ) then
 551      if ( any(vco%depths(2:vco%nLev_depth)-vco%depths(1:(vco%nLev_depth-1)) < 0.0) ) then
 552        call utl_abort('vco_setupOceanFromFile: some depth levels not in ascending order')
 553      end if
 554    end if
 555    
 556  end subroutine vco_setupOceanFromFile
 557
 558  !--------------------------------------------------------------------------
 559  ! vco_setupSfcFromFile
 560  !--------------------------------------------------------------------------
 561  subroutine vco_setupSfcFromFile(vco,beSilent)
 562    ! 
 563    !:Purpose: Initialize vertical coordinate object with information from 
 564    !           a standard file. For surface only fields.
 565    !
 566    implicit none
 567
 568    ! Arguments:
 569    type(struct_vco), pointer, intent(inout) :: vco          ! Vertical coordinate object 
 570    logical,                   intent(in)    :: beSilent
 571
 572    if (.not. beSilent) write(*,*) 'vco_setupSfcFromFile: found surface fields'
 573
 574    ! initialize some components of vco
 575    vco%vgridPresent = .false.
 576    vco%nlev_T = 0
 577    vco%nlev_M = 0
 578    vco%Vcode  = 0
 579    vco%initialized = .true.
 580
 581  end subroutine vco_setupSfcFromFile
 582
 583  !--------------------------------------------------------------------------
 584  ! vco_deallocate
 585  !--------------------------------------------------------------------------
 586  subroutine vco_deallocate(vco)
 587    !
 588    !:Purpose: Deallocate vertical coordinate object
 589    !
 590    implicit none
 591
 592    ! Arguments:
 593    type(struct_vco), pointer, intent(inout) :: vco ! Vertical coordinate object
 594
 595    ! Locals:
 596    integer :: stat
 597
 598    if ( vco%vgridPresent ) then
 599      deallocate(vco%ip1_M)
 600      deallocate(vco%ip1_T)
 601      stat = vgd_free(vco%vgrid)
 602    end if
 603
 604    if ( vco%nLev_depth > 0 ) then
 605      deallocate(vco%depths)
 606      deallocate(vco%ip1_depth)
 607    end if
 608    nullify(vco)
 609
 610  end subroutine vco_deallocate
 611
 612  !--------------------------------------------------------------------------
 613  ! vco_getNumLev
 614  !--------------------------------------------------------------------------
 615  function vco_getNumLev(vco,varLevel,varName_opt) result(nlev)
 616    ! 
 617    !:Purpose: get number of vertical levels
 618    ! 
 619    implicit none
 620
 621    ! Arguments:
 622    type(struct_vco), pointer,  intent(in) :: vco         ! Vertical coordinate object
 623    character(len=*),           intent(in) :: varLevel    ! 'TH', 'MM', 'SF', 'SFMM', 'SFTH', 'DP', 'SS' or 'OT'
 624    character(len=*), optional, intent(in) :: varName_opt ! only needed for varLevel='OT'
 625    ! Result:
 626    integer :: nlev
 627
 628    ! Locals:
 629    integer :: varListIndex
 630
 631    if (varLevel == 'MM') then
 632      nlev = vco%nlev_M
 633    else if (varLevel == 'TH') then
 634      nlev = vco%nlev_T
 635    else if (varLevel == 'SF'   .or. varLevel == 'SFTH' .or. &
 636             varLevel == 'SFMM' .or. varLevel == 'SS') then
 637      nlev = 1
 638    else if (varLevel == 'OT') then
 639      if (.not. present(varName_opt)) then
 640        call utl_abort('vco_getNumLev: varName must be specified for varLevel=OT')
 641      end if
 642      varListIndex = vnl_varListIndexOther(varName_opt)
 643      nlev = vco%nlev_Other(varListIndex)
 644    else if (varLevel == 'DP') then
 645      nlev = vco%nlev_depth
 646    else
 647      call utl_abort('vco_getNumLev: Unknown variable type! ' // varLevel)
 648    end if
 649
 650  end function vco_getNumLev
 651
 652  !--------------------------------------------------------------------------
 653  ! vco_mpiBcast
 654  !--------------------------------------------------------------------------
 655  subroutine vco_mpiBcast(vco)
 656    !
 657    !:Purpose: MPI broadcast of vertical coordinate object
 658    !
 659    implicit none
 660
 661    ! Arguments:
 662    type(struct_vco), pointer, intent(inout) :: vco ! vertical coordinate object
 663
 664    ! Locals:
 665    integer :: ierr, vgd_nlev_M, vgd_nlev_T
 666    integer :: vgdig1, vgdig2, vgdig3, vgdig4, vgdip1, vgdip2, vgdip3, vgddate
 667    integer :: vgdtable_dim1, vgdtable_dim2, vgdtable_dim3
 668    character(len=12) :: vgdetik
 669    real(8), pointer :: vgdtable(:,:,:)
 670
 671    nullify(vgdtable)
 672
 673    write(*,*) 'vco_mpiBcast: starting'
 674
 675    if (mmpi_myid > 0) then
 676      if (.not.associated(vco)) then
 677        allocate(vco)
 678      else 
 679        call utl_abort('vco_mpiBcast: vco must be nullified for mpi task id > 0')
 680      end if
 681    end if
 682
 683    call rpn_comm_bcast(vco%initialized , 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
 684    call rpn_comm_bcast(vco%vgridPresent, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
 685    call rpn_comm_bcast(vco%nlev_T      , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 686    call rpn_comm_bcast(vco%nlev_M      , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 687    call rpn_comm_bcast(vco%ip1_sfc     , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 688    call rpn_comm_bcast(vco%ip1_T_2m    , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 689    call rpn_comm_bcast(vco%ip1_M_10m   , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 690    call rpn_comm_bcast(vco%nlev_depth  , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 691    call rpn_comm_bcast(vco%Vcode       , 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 692    call rpn_comm_bcast(vco%nlev_other, vnl_numvarmaxOther, 'MPI_INTEGER', 0, 'GRID', ierr)
 693    if (vco%nLev_depth > 0) then
 694      if (mmpi_myid > 0) then
 695        allocate(vco%ip1_depth(vco%nlev_depth))
 696        allocate(vco%depths(vco%nlev_depth))
 697      end if
 698      call rpn_comm_bcast(vco%ip1_depth , vco%nlev_depth, 'MPI_INTEGER', 0, 'GRID', ierr)
 699      call rpn_comm_bcast(vco%depths    , vco%nlev_depth, 'MPI_REAL8'  , 0, 'GRID', ierr)
 700    end if
 701    if (vco%vgridPresent) then
 702      if (mmpi_myid == 0) then
 703        vgd_nlev_M = size(vco%ip1_M)
 704        vgd_nlev_T = size(vco%ip1_T)
 705      end if
 706      call rpn_comm_bcast(vgd_nlev_M, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 707      call rpn_comm_bcast(vgd_nlev_T, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 708      if (mmpi_myid > 0) then
 709        allocate(vco%ip1_M(vgd_nlev_M))
 710        allocate(vco%ip1_T(vgd_nlev_T))
 711      end if
 712      if (vgd_nlev_M > 0) call rpn_comm_bcast(vco%ip1_M, vgd_nlev_M, 'MPI_INTEGER', 0, 'GRID', ierr)
 713      if (vgd_nlev_T > 0) call rpn_comm_bcast(vco%ip1_T, vgd_nlev_T, 'MPI_INTEGER', 0, 'GRID', ierr)
 714    end if
 715
 716    ! now do bcast for vgrid object
 717    if (vco%vgridPresent) then
 718
 719      if (mmpi_myid == 0) then
 720        ierr = vgd_get(vco%vgrid,'VTBL',vgdtable)
 721        vgdtable_dim1 = size(vgdtable,1)
 722        vgdtable_dim2 = size(vgdtable,2)
 723        vgdtable_dim3 = size(vgdtable,3)
 724        ierr = vgd_get(vco%vgrid,'DATE',vgddate)
 725        ierr = vgd_get(vco%vgrid,'ETIK',vgdetik)
 726        ierr = vgd_get(vco%vgrid,'IG_1',vgdig1)
 727        ierr = vgd_get(vco%vgrid,'IG_2',vgdig2)
 728        ierr = vgd_get(vco%vgrid,'IG_3',vgdig3)
 729        ierr = vgd_get(vco%vgrid,'IG_4',vgdig4)
 730        ierr = vgd_get(vco%vgrid,'IP_1',vgdip1)
 731        ierr = vgd_get(vco%vgrid,'IP_2',vgdip2)
 732        ierr = vgd_get(vco%vgrid,'IP_3',vgdip3)
 733      end if
 734
 735      ! 3D table of real*8
 736      call rpn_comm_bcast(vgdtable_dim1, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 737      call rpn_comm_bcast(vgdtable_dim2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 738      call rpn_comm_bcast(vgdtable_dim3, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 739      if (mmpi_myid > 0) allocate(vgdtable(vgdtable_dim1, vgdtable_dim2, vgdtable_dim3)) 
 740      call rpn_comm_bcast(vgdtable, size(vgdtable), 'MPI_REAL8', 0, 'GRID', ierr)
 741      ! others
 742      call rpn_comm_bcast(vgddate, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 743      call rpn_comm_bcastc(vgdetik, len(vgdetik), 'MPI_CHARACTER', 0, 'GRID', ierr)
 744      call rpn_comm_bcast(vgdig1, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 745      call rpn_comm_bcast(vgdig2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 746      call rpn_comm_bcast(vgdig3, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 747      call rpn_comm_bcast(vgdig4, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 748      call rpn_comm_bcast(vgdip1, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 749      call rpn_comm_bcast(vgdip2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 750      call rpn_comm_bcast(vgdip3, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
 751      
 752      if (mmpi_myid > 0) then
 753        ierr = vgd_new(vco%vgrid,vgdtable)
 754        ierr = vgd_put(vco%vgrid,'DATE',vgddate)
 755        ierr = vgd_put(vco%vgrid,'ETIK',vgdetik)
 756        ierr = vgd_put(vco%vgrid,'IG_1',vgdig1)
 757        ierr = vgd_put(vco%vgrid,'IG_2',vgdig2)
 758        ierr = vgd_put(vco%vgrid,'IG_3',vgdig3)
 759        ierr = vgd_put(vco%vgrid,'IG_4',vgdig4)
 760        ierr = vgd_put(vco%vgrid,'IP_1',vgdip1)
 761        ierr = vgd_put(vco%vgrid,'IP_2',vgdip2)
 762        ierr = vgd_put(vco%vgrid,'IP_3',vgdip3)
 763      end if
 764      
 765      deallocate(vgdtable) 
 766
 767    end if
 768
 769    write(*,*) 'vco_mpiBcast: done'
 770
 771  end subroutine vco_mpiBcast
 772
 773  !--------------------------------------------------------------------------
 774  ! vco_equal
 775  !--------------------------------------------------------------------------
 776  function vco_equal(vco1,vco2) result(equal)
 777    !
 778    !:Purpose: Compare two vertical grid object and provide a logical result if they are equal or not
 779    !
 780    implicit none
 781  
 782    ! Arguments:
 783    type(struct_vco), pointer, intent(in) :: vco1 ! vertical coordinate object one
 784    type(struct_vco), pointer, intent(in) :: vco2 ! vertical coordinate object two
 785    ! Result:
 786    logical                   :: equal
 787
 788    equal = .true.
 789
 790    equal = equal .and. (vco1%Vcode == vco2%Vcode)
 791    if (.not. equal) then
 792      write(*,*) 'vco_equal: Vcode not equal'
 793      return
 794    end if
 795    if ( vco1%vgridPresent .and. vco2%vgridPresent ) then
 796       equal = equal .and. (vco1%vgrid == vco2%vgrid)
 797       if (.not. equal) then
 798          write(*,*) 'vco_equal: vgrid not equal'
 799          return
 800       end if
 801    end if
 802
 803    ! Even if vgrid defined, not enough just to compare vgrid, must compare everything
 804    equal = equal .and. (vco1%nlev_T == vco2%nlev_T)
 805    if (.not. equal) then
 806       write(*,*) 'vco_equal: nlev_T not equal', vco1%nlev_T, vco2%nlev_T
 807       return
 808    end if
 809    equal = equal .and. (vco1%nlev_M == vco2%nlev_M)
 810    if (.not. equal) then
 811       write(*,*) 'vco_equal: nlev_M not equal', vco1%nlev_M, vco2%nlev_M
 812       return
 813    end if
 814    if (vco1%vgridPresent .and. vco2%vgridPresent .and. &
 815        vco1%nlev_T > 0 .and. vco2%nlev_T > 0) then
 816      equal = equal .and. all(vco1%ip1_T(:) == vco2%ip1_T(:))
 817      if (.not. equal) then
 818        write(*,*) 'vco_equal: ip1_T not equal'
 819        return
 820      end if
 821      equal = equal .and. all(vco1%ip1_M(:) == vco2%ip1_M(:))
 822      if (.not. equal) then
 823        write(*,*) 'vco_equal: ip1_M not equal'
 824        return
 825      end if
 826      equal = equal .and. (vco1%ip1_sfc == vco2%ip1_sfc)
 827      if (.not. equal) then
 828        write(*,*) 'vco_equal: ip1_sfc not equal'
 829        return
 830      end if
 831      if (vco1%Vcode == 5002 .or. vco1%Vcode == 5005 .or. vco1%Vcode == 5100) then
 832        equal = equal .and. hybridCoefEqualOrNot(vco1, vco2)
 833        if (.not. equal) then
 834          write(*,*) 'vco_equal: hybrid parameters are not equal'
 835          return
 836        end if
 837      end if
 838    end if
 839
 840    ! For ocean fields, check depth levels
 841    if (vco1%nLev_depth > 0) then
 842      equal = equal .and. all(vco1%depths(:) == vco2%depths(:))
 843      if (.not. equal) then
 844        write(*,*) 'vco_equal: ocean depth levels are not equal'
 845        return
 846      end if
 847    end if
 848
 849  end function vco_equal
 850
 851  !--------------------------------------------------------------------------
 852  ! vco_subsetOrNot
 853  !--------------------------------------------------------------------------
 854  function vco_subsetOrNot(vco_template, vco_full) result(subset)
 855    !
 856    !:Purpose: This function determines if vco_template is a subset of vco_full.
 857    !
 858    implicit none
 859    
 860    ! Arguments:
 861    type(struct_vco), pointer, intent(in)  :: vco_full     ! vertical coordinate object full
 862    type(struct_vco), pointer, intent(in)  :: vco_template ! vertical coordinate object template
 863    ! Result:
 864    logical :: subset
 865
 866    ! Locals:
 867    integer, allocatable :: THlevelWanted(:), MMlevelWanted(:)
 868
 869    !
 870    !- Compare the vCode
 871    !
 872    if (vco_template%Vcode /= vco_full%Vcode) then
 873      subset = .false.
 874      return
 875    end if
 876
 877    !
 878    !- Check if there are any thermo or momentum levels
 879    !
 880    if ( (vco_template%nlev_T == 0) .and. (vco_template%nlev_M == 0) ) then
 881      subset = .false.
 882      return
 883    end if
 884
 885    !
 886    !- Compare the IP1s
 887    !
 888    allocate(THlevelWanted(vco_template%nlev_T))
 889    allocate(MMlevelWanted(vco_template%nlev_M))
 890
 891    call vco_levelMatchingList( THlevelWanted, MMlevelWanted, & ! OUT
 892                                vco_template, vco_full )        ! IN
 893
 894    if (any(THlevelWanted == -1) .or. any(MMlevelWanted == -1)) then
 895      subset = .false.
 896      return
 897    end if
 898
 899    deallocate(MMlevelWanted)
 900    deallocate(THlevelWanted)
 901
 902    !
 903    !- For hybrid coordinates, compare additional grid parameters
 904    !
 905    if ( .not. hybridCoefEqualOrNot(vco_template, vco_full) ) then
 906      subset = .false.
 907      return
 908    end if
 909
 910    !
 911    !- When reaching this point, we assume that we have a subset
 912    !
 913    subset = .true.
 914
 915  end function vco_subsetOrNot
 916
 917  !--------------------------------------------------------------------------
 918  ! hybridCoefEqualOrNot
 919  !--------------------------------------------------------------------------
 920  function hybridCoefEqualOrNot(vco1, vco2) result(equal)
 921    !
 922    !:Purpose: To compare two vertical coordinate hybrid coefficient object 
 923    !
 924    implicit none
 925
 926    ! Arguments:
 927    type(struct_vco), pointer, intent(in)  :: vco1 ! vertical coordinate object one
 928    type(struct_vco), pointer, intent(in)  :: vco2 ! vertical coordinate object two
 929    ! Result:
 930    logical :: equal
 931
 932    ! Locals:
 933    real(8) :: ptop1, ptop2
 934    real(8), pointer :: coefA1(:), coefA2(:)
 935    real(8), pointer :: coefB1(:), coefB2(:)
 936    real :: coefR11, coefR12
 937    real :: coefR21, coefR22
 938    integer :: stat, levIndex
 939
 940    if (vco1%Vcode == 5002) then
 941      !- Ptop
 942      stat = vgd_get(vco1%vgrid,key='PTOP - top level pressure',value=ptop1)
 943      stat = vgd_get(vco2%vgrid,key='PTOP - top level pressure',value=ptop2)
 944      if (ptop1 /= ptop2) then
 945        equal = .false.
 946        return
 947      end if
 948    end if
 949
 950    if (vco1%Vcode == 5002 .or. vco1%Vcode == 5005 .or. vco1%Vcode == 5100) then
 951
 952      !- Pref
 953      stat = vgd_get(vco1%vgrid,key='PREF - reference pressure',value=ptop1)
 954      stat = vgd_get(vco2%vgrid,key='PREF - reference pressure',value=ptop2)
 955      if (ptop1 /= ptop2) then
 956        equal = .false.
 957        return
 958      end if
 959      !- R-coef 1
 960      stat = vgd_get(vco1%vgrid,key='RC_1 - first R-coef value',value=coefR11)
 961      stat = vgd_get(vco2%vgrid,key='RC_1 - first R-coef value',value=coefR12)
 962      if (coefR11 /= coefR12) then
 963        equal = .false.
 964        return
 965      end if
 966      !- R-coef 2
 967      stat = vgd_get(vco1%vgrid,key='RC_2 - second R-coef value',value=coefR21)
 968      stat = vgd_get(vco2%vgrid,key='RC_2 - second R-coef value',value=coefR22)
 969      if (coefR21 /= coefR22) then
 970        equal = .false.
 971        return
 972      end if
 973      !- A
 974      nullify(coefA1)
 975      nullify(coefA2)
 976      stat = vgd_get(vco1%vgrid,key='CA_M - vertical A coefficient (m)',value=coefA1)
 977      stat = vgd_get(vco2%vgrid,key='CA_M - vertical A coefficient (m)',value=coefA2)
 978      if ( size(coefA1) /= size(coefA2) ) then
 979        equal = .false.
 980        return
 981      end if
 982      do levIndex = 1, size(coefA1)
 983        if (coefA1(levIndex) /= coefA2(levIndex)) then
 984          equal = .false.
 985          return
 986        end if
 987      end do
 988      !- B
 989      nullify(coefB1)
 990      nullify(coefB2)
 991      stat = vgd_get(vco1%vgrid,key='CB_M - vertical B coefficient (m)',value=coefB1)
 992      stat = vgd_get(vco2%vgrid,key='CB_M - vertical B coefficient (m)',value=coefB2)
 993      if ( size(coefB1) /= size(coefB2) ) then
 994        equal = .false.
 995        return
 996      end if
 997      do levIndex = 1, size(coefB1)
 998        if (coefB1(levIndex) /= coefB2(levIndex)) then
 999          equal = .false.
1000          return
1001        end if
1002      end do
1003
1004    end if
1005
1006    !
1007    !- When reaching this point, we assume that they are equal
1008    !
1009    equal = .true.
1010
1011  end function hybridCoefEqualOrNot
1012
1013  !--------------------------------------------------------------------------
1014  ! vco_levelMatchingList
1015  !--------------------------------------------------------------------------
1016  subroutine vco_levelMatchingList(THmatchingList, MMmatchingList, vco1, vco2)
1017    !
1018    !:Purpose: This subroutine returns arrays of array indices of the levels (ip1s) in vco2 
1019    !           corresponding with the levels (ip1s) in vco1
1020    !
1021    implicit none
1022
1023    ! Arguments:
1024    type(struct_vco), pointer, intent(in)  :: vco1                        ! vertical coordinate object one
1025    type(struct_vco), pointer, intent(in)  :: vco2                        ! vertical coordinate object two
1026    integer,                   intent(out) :: THmatchingList(vco1%nlev_T) ! TH matching list
1027    integer,                   intent(out) :: MMmatchingList(vco1%nlev_M) ! MM matching list
1028
1029    ! Locals:
1030    integer :: levIndex1, levIndex2
1031
1032    !
1033    !- Do momentum levels...
1034    !
1035    MMmatchingList(:) = -1
1036    do levIndex1 = 1, vco1%nlev_M
1037      do levIndex2 =  1, vco2%nlev_M
1038        if ( (vco2%ip1_M(levIndex2) == vco1%ip1_M(levIndex1)) .or. &
1039             (vco2%ip1_M(levIndex2) == vco2%ip1_M_10m .and.        &
1040              vco1%ip1_M(levIndex1) == vco1%ip1_M_10m) ) then
1041          MMmatchingList(levIndex1) = levIndex2
1042          exit
1043        end if
1044      end do
1045    end do
1046    
1047    !
1048    !- Do thermo levels...
1049    !
1050    THmatchingList(:) = -1
1051    do levIndex1 = 1, vco1%nlev_T
1052      do levIndex2 = 1, vco2%nlev_T
1053        if ( (vco2%ip1_T(levIndex2) == vco1%ip1_T(levIndex1)) .or. &
1054             (vco2%ip1_T(levIndex2) == vco2%ip1_T_2m .and.        &
1055              vco1%ip1_T(levIndex1) == vco1%ip1_T_2m) ) then 
1056          THmatchingList(levIndex1) = levIndex2
1057          exit
1058        end if
1059      end do
1060    end do
1061
1062  end subroutine vco_levelMatchingList
1063
1064  !--------------------------------------------------------------------------
1065  ! set_2m_10m_levels
1066  !--------------------------------------------------------------------------
1067  subroutine set_2m_10m_levels(vco)
1068    !
1069    !:Purpose: To set 2-m and 10-m levels
1070    !
1071    implicit none
1072
1073    ! Arguments:
1074    type(struct_vco), pointer, intent(in) :: vco ! vertical coordinate object
1075
1076    ! Locals:
1077    character(len=10) :: blk_s
1078
1079    if      (vco%Vcode == 5002) then
1080      vco%ip1_T_2m  = vco%ip1_sfc 
1081      vco%ip1_M_10m = vco%ip1_sfc
1082    else if (vco%Vcode == 5005 .or. vco%Vcode == 5100) then
1083      call convip(vco%ip1_T_2m ,  1.5, 4, 2, blk_s, .false.)
1084      call convip(vco%ip1_M_10m, 10.0, 4, 2, blk_s, .false.)
1085    else
1086      vco%ip1_T_2m  = -1
1087      vco%ip1_M_10m = -1
1088    end if
1089
1090  end subroutine set_2m_10m_levels
1091
1092end module verticalCoord_mod