LCOV - code coverage report
Current view: top level - control - getinterpnetcdfdata.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 107 0.0 %
Date: 2025-01-13 21:54:50 Functions: 0 2 0.0 %

          Line data    Source code
       1             : module getinterpnetcdfdata
       2             : 
       3             : ! Description:
       4             : !   Routines for extracting a column from a netcdf file
       5             : !
       6             : ! Author:
       7             : !
       8             : ! Modules Used:
       9             : !
      10             :   use cam_abortutils, only: endrun
      11             :   use pmgrid,         only: plev
      12             :   use cam_logfile,    only: iulog
      13             : 
      14             :   implicit none
      15             :   private
      16             : !
      17             : ! Public Methods:
      18             : !
      19             :   public getinterpncdata
      20             : 
      21             : contains
      22             : 
      23           0 : subroutine getinterpncdata( NCID, camlat, camlon, TimeIdx, &
      24             :    varName, have_surfdat, surfdat, fill_ends, scm_crm_mode, &
      25           0 :    press, npress, ps, hyam, hybm, outData, STATUS )
      26             : 
      27             : !     getinterpncdata: extracts the entire level dimension for a
      28             : !     particular lat,lon,time from a netCDF file
      29             : !     and interpolates it onto the input pressure levels, placing
      30             : !     result in outData, and the error status inx STATUS
      31             : 
      32             :    use shr_kind_mod, only: r8 => shr_kind_r8, i8 => shr_kind_i8
      33             :    use shr_scam_mod, only: shr_scam_GetCloseLatLon
      34             :    use netcdf
      35             :    implicit none
      36             : !-----------------------------------------------------------------------
      37             : 
      38             : 
      39             : !     ---------- inputs ------------
      40             : 
      41             :    integer, intent(in)  :: NCID          ! NetCDF ID
      42             :    integer, intent(in)  :: TimeIdx       ! time index
      43             :    real(r8), intent(in) :: camlat,camlon ! target lat and lon to be extracted
      44             :    logical, intent(in)  :: have_surfdat  ! is surfdat provided
      45             :    logical, intent(in)  :: fill_ends     ! extrapolate the end values
      46             :    logical, intent(in)  :: scm_crm_mode  ! scam column radiation mode
      47             :    integer, intent(in)  :: npress        ! number of dataset pressure levels
      48             :    real(r8), intent(in) :: press(npress) ! dataset pressure levels
      49             :    real(r8), intent(in) :: ps            ! surface pressure
      50             :    real(r8), intent(in) :: hyam(:)       ! dataset hybrid midpoint pressure levels
      51             :    real(r8), intent(in) :: hybm(:)       ! dataset hybrid midpoint pressure levels
      52             : 
      53             : !     ---------- outputs ----------
      54             : 
      55             :    real(r8), intent(inout)  :: outData(:)    ! interpolated output data
      56             :    integer, intent(out)   :: STATUS        ! return status of netcdf calls
      57             : 
      58             : !     -------  locals ---------
      59             : 
      60             :    real(r8)  surfdat       ! surface value to be added before interpolation
      61             :    integer nlev          ! number of levels in dataset
      62             :    integer     latIdx        ! latitude index
      63             :    integer     lonIdx        ! longitude index
      64           0 :    real(r8),allocatable :: tmp(:)
      65             :    real(r8)        closelat,closelon
      66             :    real(r8)        dx, dy, m             ! slope for interpolation of surfdat
      67             :    integer     varID
      68             :    integer     var_ndims
      69             :    integer     dims_set
      70             :    integer     i
      71             :    integer     var_dimIDs( NF90_MAX_VAR_DIMS )
      72             :    integer     start( NF90_MAX_VAR_DIMS )
      73             :    integer     count( NF90_MAX_VAR_DIMS )
      74             : 
      75             :    character   varName*(*)
      76             :    character   dim_name*( 256 )
      77             :    real(r8)        missing_val
      78             :    logical     usable_var
      79             : 
      80             : !     -------  code ---------
      81             : 
      82           0 :    call shr_scam_GetCloseLatLon(ncid,camlat,camlon,closelat,closelon,latidx,lonidx)
      83             : 
      84             : !
      85             : ! Check mode: double or single precision
      86             : !
      87             : 
      88             : !
      89             : ! Get var ID.  Check to make sure it's there.
      90             : !
      91           0 :    STATUS = NF90_INQ_VARID( NCID, varName, varID )
      92             : 
      93           0 :    if ( STATUS .NE. NF90_NOERR )  return
      94             : 
      95             : !
      96             : ! Check the var variable's information with what we are expecting
      97             : ! it to be.
      98             : !
      99             : 
     100           0 :    STATUS = NF90_INQUIRE_VARIABLE( NCID, varID, ndims=var_ndims )
     101           0 :    if ( var_ndims .GT. 4 ) then
     102           0 :       write(iulog,* ) 'ERROR - extractdata.F: The input var',varName, &
     103           0 :          'has', var_ndims, 'dimensions'
     104           0 :       STATUS = -1
     105             :    endif
     106             : 
     107             : !
     108             : !     surface variables
     109             : !
     110           0 :    if ( var_ndims .EQ. 0 ) then
     111           0 :       STATUS = NF90_GET_VAR( NCID, varID, outData )
     112           0 :       return
     113             :    endif
     114             : 
     115           0 :    STATUS = NF90_INQUIRE_VARIABLE( NCID, varID, dimids=var_dimIDs )
     116           0 :    if ( STATUS .NE. NF90_NOERR ) then
     117           0 :       write(iulog,* ) 'ERROR - extractdata.F:Cant get dimension IDs for', varName
     118           0 :       return
     119             :    endif
     120             : !
     121             : !     Initialize the start and count arrays
     122             : !
     123           0 :    dims_set = 0
     124           0 :    nlev = 1
     125           0 :    do i =  var_ndims, 1, -1
     126             : 
     127           0 :       usable_var = .false.
     128           0 :       STATUS = NF90_INQUIRE_DIMENSION( NCID, var_dimIDs( i ), dim_name )
     129             : 
     130           0 :       if ( dim_name .EQ. 'lat' ) then
     131           0 :          start( i ) =  latIdx
     132           0 :          count( i ) = 1           ! Extract a single value
     133           0 :          dims_set = dims_set + 1
     134           0 :          usable_var = .true.
     135             :       endif
     136             : 
     137           0 :       if ( dim_name .EQ. 'lon' .or. dim_name .EQ. 'ncol' .or. dim_name .EQ. 'ncol_d' ) then
     138           0 :          start( i ) = lonIdx
     139           0 :          count( i ) = 1           ! Extract a single value
     140           0 :          dims_set = dims_set + 1
     141           0 :          usable_var = .true.
     142             :       endif
     143             : 
     144           0 :       if ( dim_name .EQ. 'lev' ) then
     145           0 :          STATUS = NF90_INQUIRE_DIMENSION( NCID, var_dimIDs( i ), len=nlev )
     146           0 :          start( i ) = 1
     147           0 :          count( i ) = nlev       ! Extract all levels
     148           0 :          dims_set = dims_set + 1
     149           0 :          usable_var = .true.
     150             :       endif
     151             : 
     152           0 :       if ( dim_name .EQ. 'ilev' ) then
     153           0 :          STATUS = NF90_INQUIRE_DIMENSION( NCID, var_dimIDs( i ), len=nlev )
     154           0 :          start( i ) = 1
     155           0 :          count( i ) = nlev        ! Extract all levels
     156           0 :          dims_set = dims_set + 1
     157           0 :          usable_var = .true.
     158             :       endif
     159             : 
     160           0 :       if ( dim_name .EQ. 'time' .OR. dim_name .EQ. 'tsec' ) then
     161           0 :          start( i ) = TimeIdx
     162           0 :          count( i ) = 1           ! Extract a single value
     163           0 :          dims_set = dims_set + 1
     164             :          usable_var = .true.
     165             :       endif
     166             : 
     167           0 :       if ( usable_var .EQV. .false. ) then
     168           0 :          write(iulog,* )'ERROR - extractdata.F: The input var ',varName, &
     169           0 :             ' has an unusable dimension ', dim_name
     170           0 :          STATUS = 1
     171             :       endif
     172             :    end do
     173             : 
     174           0 :    if ( dims_set .NE. var_ndims ) then
     175           0 :       write(iulog,* )'ERROR - extractdata.F: Could not find all the', &
     176           0 :          ' dimensions for input var ', varName
     177           0 :       write(iulog,* )'Found ',dims_set, ' of ',var_ndims
     178           0 :       STATUS = 1
     179             :    endif
     180             : 
     181           0 :    allocate(tmp(nlev+1))
     182             : 
     183           0 :    STATUS = NF90_GET_VAR( NCID, varID, tmp, start, count )
     184             : 
     185           0 :    if ( STATUS .NE. NF90_NOERR ) then
     186           0 :       write(iulog,* )'ERROR - extractdata.F: Could not get data for input var ', varName
     187           0 :       return
     188             :    endif
     189             : 
     190           0 :    if ( nlev .eq. 1 ) then
     191           0 :       outdata(1) = tmp(1)
     192           0 :       return                 ! no need to do interpolation
     193             :    endif
     194             : !   if ( use_camiop .and. nlev.eq.plev) then
     195           0 :    if ( nlev.eq.plev .or. nlev.eq.plev+1) then
     196           0 :       outData(:nlev)= tmp(:nlev)! no need to do interpolation
     197             :    else
     198             : !
     199             : !     add the surface data if available, else
     200             : !     fill in missing surface data by extrapolation
     201             : !
     202           0 :       if(.not.scm_crm_mode) then
     203           0 :          if ( have_surfdat ) then
     204           0 :             tmp(npress) = surfdat
     205             :          else
     206           0 :             dy = press(npress-1) - press(npress-2)
     207           0 :             dx = tmp(npress-1) - tmp(npress-2)
     208           0 :             if ( dx .ne. 0.0_r8 ) then
     209           0 :                m = dy/dx
     210           0 :                tmp(npress) = ((press(npress) - press(npress-1)) / m ) + tmp(npress-1)
     211             :             else
     212           0 :                tmp(npress) = tmp(npress-1)
     213             :             endif
     214           0 :             surfdat = tmp(npress)
     215             :          endif
     216             :       endif
     217             : 
     218             : #if DEBUG > 1
     219             : !
     220             : !     check data for missing values
     221             : !
     222             : 
     223             :       STATUS = NF90_GET_ATT( NCID, varID, 'missing_value', missing_val )
     224             :       if ( STATUS .NE. NF90_NOERR ) then
     225             :          missing_val = -9999999.0_r8
     226             :       endif
     227             : !
     228             : ! reset status to zero
     229             : !
     230             :       STATUS = 0
     231             : !
     232             :       do i=1, npress
     233             :          if ( tmp(i) .eq. missing_val ) then
     234             :             write(iulog,*) 'ERROR - missing value found in ', varname
     235             :             write(iulog,*) 'time,lat,lon,lev = ' ,timeidx, latidx, lonidx, i
     236             :             stop
     237             :          endif
     238             :       enddo
     239             : #endif
     240             : !
     241           0 :       call interplevs( tmp(:npress), press, npress, ps, fill_ends, hyam, hybm, outdata )
     242             : 
     243             :    endif
     244             : 
     245           0 :    deallocate(tmp)
     246           0 :    return
     247           0 :  end subroutine getinterpncdata
     248             : 
     249           0 : subroutine interplevs( inputdata,   dplevs,   nlev, &
     250           0 :                        ps, fill_ends, hyam, hybm, outdata)
     251             : 
     252             :    use shr_kind_mod, only: r8 => shr_kind_r8, i8 => shr_kind_i8
     253             :    use interpolate_data, only: lininterp
     254             :    implicit none
     255             : 
     256             : !
     257             : !     WARNING: ps, siga and sigb must be initialized before calling this routine
     258             : !
     259             : 
     260             : !------------------------------Commons----------------------------------
     261             : 
     262             : !-----------------------------------------------------------------------
     263             : 
     264             : 
     265             : !     ------- inputs -----------
     266             :    integer, intent(in) :: nlev                 ! num press levels in dataset
     267             : 
     268             :    real(r8), intent(in) :: ps                  ! surface pressure
     269             :    real(r8), intent(in) :: hyam(:)             ! a midpoint pressure
     270             :    real(r8), intent(in) :: hybm(:)             ! b midpoint pressure
     271             :    real(r8), intent(in) :: inputdata(nlev)     ! data from netcdf dataset
     272             :    real(r8), intent(in) :: dplevs(nlev)        ! input data pressure levels
     273             : 
     274             :    logical, intent(in) :: fill_ends            ! fill in missing end values(used for
     275             :                                                ! global model datasets)
     276             : 
     277             : 
     278             : ! ------- outputs ----------
     279             :    real(r8), intent(inout) :: outdata(:)      ! interpolated column data
     280             : 
     281             : ! ------- locals -----------
     282             : 
     283             :    real(r8) mplevs( PLEV )
     284             :    real(r8) interpdata( PLEV )
     285             : 
     286             : 
     287             :    integer dstart_lev, dend_lev
     288             :    integer mstart_lev, mend_lev
     289             :    integer data_nlevs, model_nlevs, i
     290             :    integer STATUS
     291             : 
     292             : !
     293             : !     Initialize  model_pressure_levels.  ps should be set in the calling
     294             : !     routine to the value in the dataset
     295             : !
     296           0 :    do i = 1, plev
     297           0 :       mplevs( i ) = 1000.0_r8 * hyam( i ) + ps * hybm( i ) / 100.0_r8
     298             :    end do
     299             : !
     300             : !     the following algorithm assumes that pressures are increasing in the
     301             : !     arrays
     302             : !
     303             : !
     304             : !     Find the data pressure levels that are just outside the range
     305             : !     of the model pressure levels, and that contain valid values
     306             : !
     307             :    dstart_lev = 1
     308           0 :    do i= 1, nlev
     309           0 :       if ( dplevs(i) .LE. mplevs(1) ) dstart_lev  = i
     310             :    end do
     311             : 
     312             :    dend_lev = nlev
     313           0 :    do i= nlev, 1, -1
     314           0 :       if ( dplevs(i) .GE. mplevs(plev) ) then
     315           0 :          dend_lev  = i
     316             :       endif
     317             :    end do
     318             : !
     319             : !     Find the model pressure levels that are just inside the range
     320             : !     of the data pressure levels
     321             : !
     322             :    mstart_lev = 1
     323           0 :    do i=plev, 1, -1
     324           0 :       if ( mplevs( i ) .GE. dplevs( dstart_lev ) )  mstart_lev = i
     325             :    end do
     326             : 
     327             :    mend_lev = plev
     328           0 :    do i=1,plev
     329           0 :       if ( mplevs( i ) .LE. dplevs( dend_lev ) ) mend_lev = i
     330             :    end do
     331             : 
     332           0 :    data_nlevs = dend_lev - dstart_lev +1
     333           0 :    model_nlevs = mend_lev - mstart_lev +1
     334             : 
     335           0 :    call lininterp (inputdata(dstart_lev:dend_lev),dplevs(dstart_lev:dend_lev),data_nlevs, &
     336           0 :                    interpdata,mplevs(mstart_lev:mend_lev),model_nlevs)
     337             : !
     338             : !     interpolate data onto the model pressure levels
     339             : !
     340             : !!$   call lininterp (inputdata,dplevs,nlev, &
     341             : !!$                outdata(:plev),mplevs,plev)
     342           0 :    do i=1 , model_nlevs
     343           0 :       outdata( i+mstart_lev-1 ) = interpdata( i )
     344             :    end do
     345             : !
     346             : !     fill in the missing end values
     347             : !           (usually  done if this is global model dataset)
     348             : !
     349           0 :    if ( fill_ends ) then
     350           0 :       do i=1, mstart_lev
     351           0 :          outdata(i) = inputdata(1)
     352             :       end do
     353           0 :       do i= mend_lev, plev
     354           0 :          outdata(i) = inputdata(nlev)
     355             :       end do
     356             :    end if
     357             : 
     358           0 :    return
     359             : end subroutine interplevs
     360             : end module getinterpnetcdfdata

Generated by: LCOV version 1.14