!--------------------------------------- LICENCE BEGIN -----------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------


module columnData_mod 46,4
  use mpi_mod
  use varNameList_mod
  use verticalCoord_mod
  use MathPhysConstants_mod
  implicit none
  save
  private

  ! public variables and types
  public :: rhumin, struct_columnData

  ! public subroutines and functions
  public :: col_setup, col_allocate, col_deallocate
  public :: col_varExist, col_getOffsetFromVarno
  public :: col_getNumLev, col_getNumCol
  public :: col_getPressure, col_getPressureDeriv, col_calcPressure, col_vintProf, col_getHeight, col_getMountain, col_setMountain
  public :: col_getLatLon, col_setLatLon, col_copyLatLon
  public :: col_zero, col_fillmvo, col_getAllColumns, col_getColumn, col_getElem, col_getVco, col_setVco

  ! public entities accessed through inheritance
  public :: struct_vco, vco_SetupFromFile, vco_getNumLev
  public :: vnl_varnameFromVarnum, vnl_vartypeFromVarnum
  public :: vgd_get,vgd_levels,vgd_ok,vgd_dpidpis,vgd_write

  type struct_columnData
    integer           :: numCol
    logical           :: allocated=.false.
    logical           :: mpi_local
    real*8,pointer    :: all(:,:)
    real*8,pointer    :: gz_T(:,:),gz_M(:,:)
    real*8,pointer    :: rppobs_T(:,:),rppobs_M(:,:)
    real*8,pointer    :: dP_dPsfc_T(:,:),dP_dPsfc_M(:,:)
    real*8,pointer    :: oltv(:,:,:)    ! Tangent linear operator of virtual temperature
    real*8,pointer    :: rtapfac(:,:)   ! Background surface pressure dependant factor used for Temperature to Phi calc.
    real*8,pointer    :: lat(:),lon(:)
    real(8),pointer   :: latRot(:),lonRot(:)
    real(8),pointer   :: ypos(:)
    real(8),pointer   :: xpos(:)
    type(struct_vco), pointer  :: vco => null()
    integer,pointer   :: varOffset(:),varNumLev(:)
  end type struct_columnData

  real*8 :: rhumin
  logical nmvoexist(vnl_numvarmax)
  integer :: nvo3d,nvo2d

  contains



    SUBROUTINE col_setup 1,5
      implicit none
      INTEGER JVAR, IPOS
      integer :: fnom,fclos,nulnam,ierr
      CHARACTER(len=4) :: CMVONEED(VNL_NUMVARMAX)
      NAMELIST /NAMSTATEO/CMVONEED,rhumin

      if(mpi_myid.eq.0) write(*,*) 'col_setup: List of known (valid) variable names'
      if(mpi_myid.eq.0) write(*,*) 'col_setup: varNameList3D=',vnl_varNameList3D
      if(mpi_myid.eq.0) write(*,*) 'col_setup: varNameList2D=',vnl_varNameList2D
      if(mpi_myid.eq.0) write(*,*) 'col_setup: varNameList  =',vnl_varNameList

      ! Read NAMELIST NAMSTATEO to find which fields are needed

      cmvoneed(:) = '    '
      rhumin = MPC_MINIMUM_HU_R8

      nulnam=0
      ierr=fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
      read(nulnam,nml=namstateo,iostat=ierr)
      if(ierr.ne.0) call abort3d('col_setup: Error reading namelist')
      if(mpi_myid.eq.0) write(*,nml=namstateo)
      ierr=fclos(nulnam)

      nvo3d  = 0
      nvo2d  = 0

      if(varneed('GZ')) call abort3d('col_setup: GZ can no longer be included as a variable in columnData!')

      do jvar = 1, vnl_numvarmax3D
        if (varneed(vnl_varNameList3D(jvar))) then
          nmvoexist(jvar) = .true.
          nvo3d = nvo3d + 1
        else
          nmvoexist(jvar) = .false.
        endif
      enddo

      do jvar = 1, vnl_numvarmax2D
        if (varneed(vnl_varNameList2D(jvar))) then
          nmvoexist(jvar+vnl_numvarmax3D) = .true.
          nvo2d = nvo2d + 1
        else
          nmvoexist(jvar+vnl_numvarmax3D) = .false.
        endif
      enddo

      if(mpi_myid.eq.0) write(*,*) 'col_setup: nvo3d,nvo2d=',nvo3d,nvo2d
      if(mpi_myid.eq.0) write(*,*) 'col_setup: nmvoexist =',nmvoexist

      if(mpi_myid.eq.0) WRITE(*,*)' DIMENSIONS OF MODEL STATE ARRAYS:'
      if(mpi_myid.eq.0) WRITE(*,FMT=9120) NVO3D,NVO2D
 9120 FORMAT(4X,'  NVO3D =',I6,' NVO2D    =',I6)

      CONTAINS


        LOGICAL FUNCTION VARNEED(varName) 6
          character(len=*) :: varName
          integer :: jvar
 
          varneed=.false.
          do jvar=1,VNL_NUMVARMAX
            if (trim(varName).eq.trim(cmvoneed(jvar))) then
              varneed=.true.
            endif
          enddo

        END FUNCTION VARNEED

    END SUBROUTINE col_setup



    SUBROUTINE col_zero(column) 1
      IMPLICIT NONE
      type(struct_columnData) :: column

      if(column%numCol.gt.0) then
        column%all(:,:)=0.0d0
        column%rppobs_M(:,:)=0.0d0
        column%rppobs_T(:,:)=0.0d0
        column%gz_M(:,:)=0.0d0
        column%gz_T(:,:)=0.0d0
      endif

    END SUBROUTINE col_zero



    SUBROUTINE col_allocate(column,numCol,mpi_local) 6,11
      IMPLICIT NONE

      type(struct_columnData) :: column
      integer, intent(in)           :: numCol
      logical, optional             :: mpi_local
      integer :: nkgdimo,ier

      integer iloc,jvar,jvar2

      column%numCol = numCol
      if(present(mpi_local)) then
        column%mpi_local=mpi_local
      else
        column%mpi_local=.true.
        if(mpi_myid.eq.0) write(*,*) 'col_allocate: assuming columnData is mpi-local'
      endif

      if(.not.column%vco%initialized) then
        call abort3d('col_allocate: VerticalCoord has not been initialized!')
      endif

      allocate(column%varOffset(vnl_numvarmax))
      column%varOffset(:)=0
      allocate(column%varNumLev(vnl_numvarmax))
      column%varNumLev(:)=0

      iloc=0
      do jvar = 1, vnl_numvarmax3d
        if(nmvoexist(jvar)) then
          column%varOffset(jvar)=iloc
          column%varNumLev(jvar)=col_getNumLev(column,vnl_vartypeFromVarname(vnl_varNameList(jvar)))
          iloc = iloc + column%varNumLev(jvar)
        endif
      enddo
      do jvar2 = 1, vnl_numvarmax2d
        jvar=jvar2+vnl_numvarmax3d
        if(nmvoexist(jvar)) then
          column%varOffset(jvar)=iloc
          column%varNumLev(jvar)=1
          iloc = iloc + 1
        endif
      enddo
      nkgdimo=iloc

      if(column%numCol.le.0) then
        write(*,*) 'col_allocate: number of columns is zero, not allocated'
      else         
        allocate(column%all(nkgdimo,column%numCol))
        column%all(:,:)=0.0d0

        allocate(column%gz_T(col_getNumLev(column,'TH'),column%numCol))
        allocate(column%gz_M(col_getNumLev(column,'MM'),column%numCol))
        column%gz_T(:,:)=0.0d0
        column%gz_M(:,:)=0.0d0

        allocate(column%rppobs_T(col_getNumLev(column,'TH'),column%numCol))
        allocate(column%rppobs_M(col_getNumLev(column,'MM'),column%numCol))
        column%rppobs_T(:,:)=0.0d0
        column%rppobs_M(:,:)=0.0d0

        allocate(column%dP_dPsfc_T(col_getNumLev(column,'TH'),column%numCol))
        allocate(column%dP_dPsfc_M(col_getNumLev(column,'MM'),column%numCol))
        column%dP_dPsfc_T(:,:)=0.0d0
        column%dP_dPsfc_M(:,:)=0.0d0

        allocate(column%lat(column%numCol))
        allocate(column%lon(column%numCol))
        allocate(column%latRot(column%numCol))
        allocate(column%lonRot(column%numCol))
        allocate(column%ypos(column%numCol))
        allocate(column%xpos(column%numCol))
        column%lat(:)=0.0d0
        column%lon(:)=0.0d0
        column%latRot(:)=0.0d0
        column%lonRot(:)=0.0d0
        column%ypos(:)=0.0d0
        column%xpos(:)=0.0d0

        allocate(column%oltv(2,col_getNumLev(column,'TH'),numCol))
        column%oltv(:,:,:)=0.0d0
        allocate(column%rtapfac(col_getNumLev(column,'TH'),numCol))
        column%rtapfac(:,:)=0.0d0

      endif
 
      if(mpi_myid.eq.0) write(*,*) 'col_allocate: nkgdimo = ',nkgdimo
      if(mpi_myid.eq.0) write(*,*) 'col_allocate: varOffset=',column%varOffset
      if(mpi_myid.eq.0) write(*,*) 'col_allocate: varNumLev=',column%varNumLev

      column%allocated=.true.

      RETURN
    END SUBROUTINE col_allocate



    SUBROUTINE col_deallocate(column) 5
      IMPLICIT NONE

      type(struct_columnData) :: column

      deallocate(column%varOffset)
      deallocate(column%varNumLev)

      if(column%numCol.gt.0) then
        deallocate(column%all)
        deallocate(column%gz_T)
        deallocate(column%gz_M)
        deallocate(column%rppobs_T)
        deallocate(column%rppobs_M)
        deallocate(column%dP_dPsfc_T)
        deallocate(column%dP_dPsfc_M)
        deallocate(column%lat)
        deallocate(column%lon)
        deallocate(column%latRot)
        deallocate(column%lonRot)
        deallocate(column%ypos)
        deallocate(column%xpos)
        deallocate(column%oltv)
        deallocate(column%rtapfac)
      endif

      column%allocated=.false.

      RETURN
    END SUBROUTINE col_deallocate



    SUBROUTINE col_fillmvo(columnghr,pvar,varName,varType) 9,13
    !
    !**s/r fillmvo - Fill in values for a complete set of columns at once
    !
    !Arguments
    !
    !       input:
    !             columnghr          : HR or BG column object
    !             VARNAME (character*4): NOMVAR of the state variable
    !             PVAR(knlev,knobs)   : Variable to transfer in COMMVO(G)(HR)
    implicit none

    type(struct_columnData) :: columnghr
    real*8 pvar(:,:)
    character(len=*) :: varName
    character(len=*), optional :: varType

    integer jobs,jlev
    real*8, pointer :: column_ptr(:)

    ! Pressure
    select case(trim(varName))
    case('PR')
      if(present(varType)) then
        if(varType.eq.'TH') then
          do jobs = 1,columnghr%numCol
            do jlev = 1,col_getNumLev(columnghr,'TH')
              columnghr%rppobs_T(jlev,jobs) = pvar(jlev,jobs)
            enddo
          enddo
        elseif(varType.eq.'MM') then
          do jobs = 1,columnghr%numCol
            do jlev = 1,col_getNumLev(columnghr,'MM')
              columnghr%rppobs_M(jlev,jobs) = pvar(jlev,jobs)
            enddo
          enddo
        else
          call abort3d('col_fillmvo: must specify varType TH or MM for Pressure! ' // varType)
        endif
      else
        call abort3d('col_fillmvo: must specify varType for Pressure!')
      endif

    ! Height
    case('GZ')
      if(present(varType)) then
        if(varType.eq.'TH') then
          do jobs = 1,columnghr%numCol
            do jlev = 1, col_getNumLev(columnghr,'TH')
              columnghr%gz_T(jlev,jobs)=pvar(jlev,jobs)
            enddo
          enddo
        elseif(varType.eq.'MM') then
          do jobs = 1,columnghr%numCol
            do jlev = 1, col_getNumLev(columnghr,'MM')
              columnghr%gz_M(jlev,jobs)=pvar(jlev,jobs)
            enddo
          enddo
        else
          call abort3d('col_fillmvo: must specify varType TH or MM for GZ! ' // varType)
        endif
      else
        call abort3d('col_fillmvo: must specify varType for GZ!')
      endif

    ! All the other variables that are stored in column%all
    case default
      if(col_varExist(trim(varName))) then
        do jobs = 1,columnghr%numCol
          column_ptr => col_getColumn(columnghr,jobs,varName)
          do jlev = 1, col_getNumLev(columnghr,vnl_vartypeFromVarname(varName))
            column_ptr(jlev)=pvar(jlev,jobs) 
          enddo
        enddo

      ! Unknown variable name
      else
        call abort3d('col_fillmvo: Unknown variable name: ' // varName)
      endif

    end select

    return
    END SUBROUTINE col_fillmvo



    function col_varExist(varName) result(varExist) 12,1
      implicit none
      character(len=*), intent(in) :: varName
      logical                      :: varExist 

      if(trim(varName).eq.'PR'.or.trim(varName).eq.'GZ') then
        ! pressure and height always available
        varExist = .true.
      elseif(nmvoexist(vnl_varListIndex(varName))) then
        varExist = .true.
      else
        varExist = .false.
      endif

    end function col_varExist



    function col_getOffsetFromVarno(column,varnum) result(offset) 19,2
      implicit none
      type(struct_columnData) :: column
      integer, intent(in)     :: varnum
      integer                 :: offset

      offset=column%varOffset(vnl_varListIndex(vnl_varnameFromVarnum(varnum)))

    end function col_getOffsetFromVarno



  subroutine col_calcPressure(column) 2,11
    implicit none
    type(struct_columnData), intent(inout) :: column

    real(kind=8), allocatable :: Psfc(:,:),zppobs2(:,:)
    real(kind=8), pointer     :: zppobs1(:,:,:) => null()
    real(kind=8), pointer     :: dP_dPsfc(:,:,:) => null()
    integer :: jobs,status

    allocate(Psfc(1,col_getNumCol(column)))
    do jobs = 1,col_getNumCol(column)
      Psfc(1,jobs) = col_getElem(column,1,jobs,'P0')
    enddo

    write(*,*) 'col_calcPressure: computing pressure on staggered or UNstaggered levels'

    status=vgd_levels(column%vco%vgrid,ip1_list=column%vco%ip1_M,  &
                      levels=zppobs1,sfc_field=Psfc,in_log=.false.)
    if(status.ne.VGD_OK) call abort3d('ERROR with vgd_levels')
    allocate(zppobs2(col_getNumLev(column,'MM'),col_getNumCol(column)))
    zppobs2 = transpose(zppobs1(1,:,:))
    call col_fillmvo(column,zppobs2,'PR','MM')
    if (associated(zppobs1))  deallocate(zppobs1)
    deallocate(zppobs2)

    status=vgd_levels(column%vco%vgrid,ip1_list=column%vco%ip1_T,  &
                      levels=zppobs1,sfc_field=Psfc,in_log=.false.)
    if(status.ne.VGD_OK) call abort3d('ERROR with vgd_levels')
    allocate(zppobs2(col_getNumLev(column,'TH'),col_getNumCol(column)))
    zppobs2 = transpose(zppobs1(1,:,:))
    call col_fillmvo(column,zppobs2,'PR','TH')
    if (associated(zppobs1)) deallocate(zppobs1)
    deallocate(zppobs2)

    write(*,*) 'col_calcPressure: computing derivate of pressure wrt surface pressure'

    status = vgd_dpidpis(column%vco%vgrid,column%vco%ip1_M,dP_dPsfc,Psfc)
    column%dP_dPsfc_M(:,:) = transpose(dP_dPsfc(1,:,:))
    deallocate(dP_dPsfc)

    status = vgd_dpidpis(column%vco%vgrid,column%vco%ip1_T,dP_dPsfc,Psfc)
    column%dP_dPsfc_T(:,:) = transpose(dP_dPsfc(1,:,:))
    deallocate(dP_dPsfc)

    deallocate(Psfc)

  end subroutine col_calcPressure



  subroutine col_vintprof(column_in,column_out,varName) 3,12
    implicit none
    type(struct_columnData), intent(inout) :: column_out
    type(struct_columnData), intent(in) :: column_in
    character(len=*) :: varName

    real(kind=8), pointer :: column_ptr_in(:),column_ptr_out(:)
    character(len=2) :: varType
    real(kind=8)     :: zwb,zwt
    integer          :: jlevo,jlevi,jprof

    varType = vnl_vartypeFromVarname(varName)

    do jprof = 1, col_getNumCol(column_out)
      column_ptr_in  => col_getColumn(column_in ,jprof,varName)
      column_ptr_out => col_getColumn(column_out,jprof,varName)
      jlevi = 1
      do jlevo = 1, col_getNumLev(column_out,varType)
        jlevi = jlevi + 1
        do while(col_getPressure(column_out,jlevo,jprof,varType) .gt.  &
                 col_getPressure(column_in ,jlevi,jprof,varType) .and. &
                 jlevi .lt. col_getNumLev(column_in,varType) )
          jlevi = jlevi + 1
        enddo
        jlevi = jlevi - 1
        zwb = log(col_getPressure(column_out,jlevo,jprof,varType)/col_getPressure(column_in,jlevi,jprof,varType))/  &
              log(col_getPressure(column_in,jlevi+1,jprof,varType)/col_getPressure(column_in,jlevi,jprof,varType))
        zwt = 1. - zwb
        column_ptr_out(jlevo) = zwb*column_ptr_in(jlevi+1) + zwt*column_ptr_in(jlevi)
      enddo
    enddo

  end subroutine col_vintprof



  function col_getPressure(column,ilev,headerIndex,varType) result(pressure) 84,1
    implicit none
    type(struct_columnData), intent(in) :: column
    integer, intent(in)                 :: ilev,headerIndex
    character(len=*), intent(in)        :: varType
    real*8                              :: pressure

    if (varType .eq. 'TH') then
      pressure = column%rppobs_t(ilev,headerIndex)
    elseif (varType .eq. 'MM' ) then
      pressure = column%rppobs_m(ilev,headerIndex)
    else
      call abort3d('col_getPressure: Unknown variable type: ' // varType)
    endif

  end function col_getPressure
 


  function col_getPressureDeriv(column,ilev,headerIndex,varType) result(dP_dPsfc) 22,1
    implicit none
    type(struct_columnData), intent(in) :: column
    integer, intent(in)                 :: ilev,headerIndex
    character(len=*), intent(in)        :: varType
    real*8                              :: dP_dPsfc

    if (varType .eq. 'TH') then
      dP_dPsfc = column%dP_dPsfc_t(ilev,headerIndex)
    elseif (varType .eq. 'MM' ) then
      dP_dPsfc = column%dP_dPsfc_m(ilev,headerIndex)
    else
      call abort3d('col_getPressureDeriv: Unknown variable type: ' // varType)
    endif

  end function col_getPressureDeriv



  function col_getHeight(column,ilev,headerIndex,varType) result(height) 50,1
    implicit none
    type(struct_columnData), intent(in) :: column
    integer, intent(in)                 :: ilev,headerIndex
    character(len=*), intent(in)        :: varType
    real*8                              :: height
    integer                             :: ilev1

    if (varType .eq. 'TH') then
      height = column%gz_t(ilev,headerIndex)
    elseif (varType .eq. 'MM' ) then
      height = column%gz_m(ilev,headerIndex)
    else
      call abort3d('col_getHeight: unknown varType! ' // varType)
    endif

  end function col_getHeight



  function col_getMountain(column,headerIndex) result(height) 5,1
    implicit none
    type(struct_columnData), intent(in) :: column
    integer, intent(in)                 :: headerIndex
    real*8                              :: height

    height = column%gz_t(col_getNumLev(column,'TH'),headerIndex)

  end function col_getMountain



  subroutine col_setMountain(column,headerIndex,height) 1,2
    implicit none
    type(struct_columnData)             :: column
    integer, intent(in)                 :: headerIndex
    real*8, intent(in)                  :: height

    column%gz_t(col_getNumLev(column,'TH'),headerIndex) = height
    column%gz_m(col_getNumLev(column,'MM'),headerIndex) = height

  end subroutine col_setMountain



  subroutine col_getLatLon(column, headerIndex, Lat, Lon, & 5
                           ypos, xpos, LatRot, LonRot)
    implicit none

    type(struct_columnData)             :: column
    integer, intent(in)                 :: headerIndex
    real(8), intent(out)                :: Lat, Lon
    real(8), intent(out)                :: LatRot, LonRot
    real(8), intent(out)                :: Ypos, Xpos

    Lat    = column % lat   (headerIndex)
    Lon    = column % lon   (headerIndex)
    LatRot = column % latRot(headerIndex)
    LonRot = column % lonRot(headerIndex)
    ypos   = column % ypos  (headerIndex)
    xpos   = column % xpos  (headerIndex)

  end subroutine col_getLatLon



  subroutine col_setLatLon(column, headerIndex, Lat, Lon, & 2
                           Ypos, Xpos, LatRot, LonRot)
    implicit none

    type(struct_columnData)             :: column
    integer, intent(in)                 :: headerIndex
    real(8), intent(in)                 :: Lat,Lon
    real(8), intent(in)                 :: LatRot,LonRot
    real(8), intent(in)                 :: Ypos, Xpos

    column % lat   (headerIndex) = Lat
    column % lon   (headerIndex) = Lon
    column % latRot(headerIndex) = LatRot
    column % lonRot(headerIndex) = LonRot
    column % ypos  (headerIndex) = Ypos
    column % xpos  (headerIndex) = Xpos

  end subroutine col_setLatLon



  subroutine col_copyLatLon(column_in,column_out) 4
    implicit none
    type(struct_columnData)             :: column_in,column_out
    integer                             :: headerIndex

    do headerIndex = 1, column_in % numCol
      column_out % lat   (headerIndex) = column_in % lat   (headerIndex)
      column_out % lon   (headerIndex) = column_in % lon   (headerIndex)
      column_out % latRot(headerIndex) = column_in % latRot(headerIndex)
      column_out % lonRot(headerIndex) = column_in % lonRot(headerIndex)
      column_out % ypos  (headerIndex) = column_in % ypos  (headerIndex)
      column_out % xpos  (headerIndex) = column_in % xpos  (headerIndex)
    end do

  end subroutine col_copyLatLon



  function col_getAllColumns(column,varName) result(allColumns) 2,5
    implicit none
    type(struct_columnData), intent(in)    :: column
    character(len=*), intent(in), optional :: varName
    real*8,pointer                         :: allColumns(:,:)
    integer                                :: ilev1,ilev2

    if ( column%numCol > 0 ) then
      if(present(varName)) then
        if(trim(varName).eq.'GZ') then
          call abort3d('col_getAllColumns: Cannot call this for GZ!')
        elseif(col_varExist(varName)) then
          ilev1 = column%varOffset(vnl_varListIndex(varName))+1
          ilev2 = ilev1 - 1 + column%varNumLev(vnl_varListIndex(varName))
          allColumns => column%all(ilev1:ilev2,:)
        else
          call abort3d('col_getAllColumn: Unknown variable name! ' // varName)
        endif
      else
        allColumns => column%all(:,:)
      endif
    else
      allColumns => null()
    end if

  end function col_getAllColumns



  function col_getColumn(column,headerIndex,varName,varType) result(onecolumn) 68,8
    implicit none
    type(struct_columnData), intent(in)    :: column
    integer, intent(in)                    :: headerIndex
    character(len=*), intent(in), optional :: varName
    character(len=*), intent(in), optional :: varType
    real*8,pointer                         :: onecolumn(:)
    integer                                :: ilev1,ilev2

    if(present(varName)) then
      if(col_varExist(varName)) then

        select case(trim(varName))
        case('PR')
          if(present(varType)) then 
            if(varType.eq.'TH') then
              onecolumn => column%rppobs_T(:,headerIndex)
            elseif(varType.eq.'MM') then
              onecolumn => column%rppobs_M(:,headerIndex)
            else
              call abort3d('col_getColumn: varType must MM or TH for Pressure! ' // varType)         
            endif
          else
            call abort3d('col_getColumn: varType must be specified for Pressure!')
          endif

        case('GZ')
          if(present(varType)) then 
            if(varType.eq.'TH') then
              onecolumn => column%gz_T(:,headerIndex)
            elseif(varType.eq.'MM') then
              onecolumn => column%gz_M(:,headerIndex)
            else
              call abort3d('col_getColumn: varType must MM or TH for Height! ' // varType)         
            endif
          else
            call abort3d('col_getColumn: varType must be specified for Height!')         
          endif

        case default ! all other variable names
          ilev1 = column%varOffset(vnl_varListIndex(varName))+1
          ilev2 = ilev1 - 1 + column%varNumLev(vnl_varListIndex(varName))
          onecolumn => column%all(ilev1:ilev2,headerIndex)
        end select

      else
        call abort3d('col_getColumn: Unknown variable name! ' // varName)
      endif
    else
      onecolumn => column%all(:,headerIndex)
    endif

  end function col_getColumn



  function col_getElem(column,ilev,headerIndex,varName) result(value) 194,3
    implicit none
    type(struct_columnData), intent(in)    :: column
    integer, intent(in)                    :: ilev
    integer, intent(in)                    :: headerIndex
    character(len=*), intent(in), optional :: varName
    real*8                                 :: value

    if(present(varName)) then
      if(trim(varName).eq.'GZ') call abort3d('col_getElem: cannot call for GZ!')
      if(trim(varName).eq.'PR') call abort3d('col_getElem: cannot call for Pressure!')
      value = column%all(column%varOffset(vnl_varListIndex(varName))+ilev,headerIndex)
    else
      value = column%all(ilev,headerIndex)
    endif

  end function col_getElem



  function col_getNumLev(column,varType) result(nlev) 158,1
    implicit none
    type(struct_columnData), intent(in) :: column
    character(len=*), intent(in)        :: varType
    integer                             :: nlev

    nlev = vco_getNumLev(column%vco,varType)

  end function col_getNumLev



  function col_getNumCol(column) result(numColumn) 47
    implicit none
    type(struct_columnData), intent(in) :: column
    integer                             :: numColumn

    numColumn = column%numCol

  end function col_getNumCol



  function col_getVco(column) result(vco_ptr) 28
    implicit none
    type(struct_columnData)   :: column
    type(struct_vco), pointer :: vco_ptr

    vco_ptr => column%vco

  end function col_getVco



  subroutine col_setVco(column,vco_ptr) 6
    implicit none
    type(struct_columnData)   :: column
    type(struct_vco), pointer :: vco_ptr

    column%vco => vco_ptr

  end subroutine col_setVco

end module columnData_mod