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

              Line data    Source code
           1             : module horizontal_interpolate
           2             :
           3             : !
           4             : ! Modules Used:
           5             : !
           6             :   use shr_kind_mod,       only: r8 => shr_kind_r8
           7             :   use shr_const_mod,      only: SHR_CONST_PI
           8             :   use cam_abortutils,     only: endrun
           9             :   use scamMod,            only: single_column
          10             :   use cam_logfile,        only: iulog
          11             :   implicit none
          12             :   private
          13             :   save
          14             :
          15             :   real(r8) :: gw1(1000), gw2(1000)
          16             :
          17             :   public :: xy_interp_init, xy_interp
          18             :
          19             : contains
          20           0 :   subroutine xy_interp_init(im1,jm1,lon0,lat0,im2,jm2,weight_x,weight_y,use_flight_distance)
          21             : !------------------------------------------------------------------------------------------------------------
          22             : ! This program computes weighting functions to map a variable of (im1,jm1) resolution to (im2,jm2) resolution
          23             : ! weight_x(im2,im1) is the weighting function for zonal interpolation
          24             : ! weight_y(jm2,jm1) is the weighting function for meridional interpolation
          25             : !
          26             : ! Author: Chih-Chieh (Jack) Chen  -- May 2010
          27             : !
          28             : !------------------------------------------------------------------------------------------------------------
          29             :   implicit none
          30             :   integer,  intent(in)  :: im1, jm1, im2, jm2
          31             :   logical,  intent(in)  :: use_flight_distance   !.true. = flight distance, .false. =  all mixing ratios
          32             :   real(r8), intent(in)  :: lon0(im1), lat0(jm1)
          33             :   real(r8), intent(out) :: weight_x(im2,im1), weight_y(jm2,jm1)
          34             :
          35           0 :   real(r8) :: lon1(im1), lat1(jm1)
          36           0 :   real(r8) :: lon2(im2), lat2(jm2)
          37           0 :   real(r8) :: slon1(im1+1), slon2(im2+1), slat1(jm1+1), slat2(jm2+1)
          38             :   real(r8) :: x1_west, x1_east, x2_west, x2_east
          39             :   real(r8) :: y1_south, y1_north, y2_south, y2_north
          40             :   integer  :: i1, j1, i2, j2
          41             :
          42           0 :   weight_x(:,:) = 0.0_r8
          43           0 :   weight_y(:,:) = 0.0_r8
          44             :
          45             : ! lon0 & lat0 are longitude & latitude on the source mesh in radians
          46             : ! convert lon1, lat1 from radians to degrees
          47           0 :   lon1(:) = lon0(:)/SHR_CONST_PI*180.0_r8
          48           0 :   lat1(:) = lat0(:)/SHR_CONST_PI*180.0_r8
          49             :
          50             : ! set up lon2, lat2 (target mesh), in CAM convention
          51           0 :   do i2=1,im2
          52           0 :    lon2(i2) = (float(i2)-1.0_r8)*360.0_r8/float(im2)
          53             :   enddo
          54           0 :   do j2=1,jm2
          55           0 :    lat2(j2) = -90.0_r8+(float(j2)-1.0_r8)*180.0_r8/(float(jm2)-1.0_r8)
          56             :   enddo
          57             :
          58             :
          59             : ! set up staggered longitudes (cell edges in x)
          60           0 :   do i1=2,im1
          61           0 :         slon1(i1) = (lon1(i1-1)+lon1(i1))/2.0_r8
          62             :   enddo
          63           0 :   slon1(1) = lon1(1)-(lon1(2)-lon1(1))/2.0_r8
          64           0 :   slon1(im1+1) = lon1(im1)+(lon1(im1)-lon1(im1-1))/2.0_r8
          65             :
          66           0 :   do i2=2,im2
          67           0 :         slon2(i2) = (lon2(i2-1)+lon2(i2))/2.0_r8
          68             :   enddo
          69           0 :   slon2(1) = lon2(1)-(lon2(2)-lon2(1))/2.0_r8
          70           0 :   slon2(im2+1) = lon2(im2)+(lon2(im2)-lon2(im2-1))/2.0_r8
          71             :
          72             : ! set up staggered lattiudes (cell edges in y)
          73           0 :   slat1(1)=-90.0_r8
          74           0 :   do j1=2,jm1
          75           0 :         slat1(j1) = (lat1(j1-1)+lat1(j1))/2.0_r8
          76             :   enddo
          77           0 :   slat1(jm1+1)=90.0_r8
          78             :
          79           0 :   slat2(1)=-90.0_r8
          80           0 :   do j2=2,jm2
          81           0 :         slat2(j2)=(lat2(j2-1)+lat2(j2))/2.0_r8
          82             :   enddo
          83           0 :   slat2(jm2+1)=90.0_r8
          84             :
          85             : ! compute Guassian weight for two meshes (discrete form of cos(lat).)
          86           0 :   do j1=1,jm1
          87           0 :         gw1(j1) = sin(slat1(j1+1)/180.0_r8*SHR_CONST_PI)-sin(slat1(j1)/180.0_r8*SHR_CONST_PI)
          88             :   enddo
          89             :
          90           0 :   do j2=1,jm2
          91           0 :         gw2(j2) = sin(slat2(j2+1)/180.0_r8*SHR_CONST_PI)-sin(slat2(j2)/180.0_r8*SHR_CONST_PI)
          92             :   enddo
          93             :
          94             :
          95             : ! add 360 to slon1 and slon2
          96           0 :   slon1(:) = slon1(:)+360.0_r8
          97           0 :   slon2(:) = slon2(:)+360.0_r8
          98             :
          99           0 :  do i2=1,im2
         100             :
         101             : ! target grid east-west boundaries
         102           0 :   x2_west=slon2(i2)
         103           0 :   x2_east=slon2(i2+1)
         104             :
         105           0 :   do i1=1,im1
         106             :
         107             : ! source grid east-west boundaries
         108           0 :    x1_west=slon1(i1)
         109           0 :    x1_east=slon1(i1+1)
         110             :
         111             : ! check if there is any overlap between the source grid and the target grid
         112             : ! if no overlap, then weighting is zero
         113             : ! there are three scenarios overlaps can take place
         114           0 :    if( (x1_west>=x2_west).and.(x1_east<=x2_east) ) then
         115             : ! case 1:
         116             : !                x1_west             x1_east
         117             : !                  |-------------------|
         118             : !            |---------------------------------|
         119             : !          x2_west                           x2_east
         120           0 :     if(use_flight_distance) then
         121           0 :      weight_x(i2,i1) = 1.0_r8
         122             :     else
         123           0 :      weight_x(i2,i1) =  (x1_east-x1_west)/(x2_east-x2_west)
         124             :     endif
         125           0 :    elseif ( (x1_west>=x2_west).and.(x1_west<x2_east) ) then
         126             : ! case 2:
         127             : !                x1_west                          x1_east
         128             : !                  |--------------------------------|
         129             : !            |---------------------------------|
         130             : !          x2_west                           x2_east
         131           0 :    if(use_flight_distance) then
         132           0 :      weight_x(i2,i1) = (x2_east-x1_west)/(x1_east-x1_west)
         133             :    else
         134           0 :      weight_x(i2,i1) = (x2_east-x1_west)/(x2_east-x2_west)
         135             :    endif
         136           0 :    elseif ( (x1_east>x2_west).and.(x1_east<=x2_east) ) then
         137             : ! case 3:
         138             : !       x1_west                          x1_east
         139             : !         |--------------------------------|
         140             : !                |---------------------------------|
         141             : !              x2_west                           x2_east
         142           0 :    if(use_flight_distance) then
         143           0 :      weight_x(i2,i1) = (x1_east-x2_west)/(x1_east-x1_west)
         144             :    else
         145           0 :      weight_x(i2,i1) = (x1_east-x2_west)/(x2_east-x2_west)
         146             :    endif
         147           0 :    elseif ( (x1_east>x2_east).and.(x1_west<x2_west) ) then
         148             : ! case 4:
         149             : !       x1_west                          x1_east
         150             : !         |--------------------------------|
         151             : !                |--------------------|
         152             : !              x2_west              x2_east
         153           0 :      weight_x(i2,i1) = 1._r8
         154             :    endif
         155             :
         156             :    enddo
         157             :   enddo
         158             :
         159             :
         160             : ! consider end points
         161           0 :       if(slon1(im1+1)>slon2(im2+1)) then
         162             : ! case 1:
         163             : !           slon1(im1)                slon1(im1+1) <--- end point
         164             : !              |-------------------------|
         165             : !           |----------------|......................|
         166             : !        slon2(im2)         slon2(im2+1)        slon2(2)  (note: slon2(im2+1) = slon2(1))
         167           0 :          if(use_flight_distance) then
         168           0 :             weight_x(1,im1)= weight_x(1,im1)+(slon1(im1+1)-slon2(im2+1))/(slon1(im1+1)-slon1(im1))
         169             :          else
         170           0 :             weight_x(1,im1)= weight_x(1,im1)+(slon1(im1+1)-slon2(im2+1))/(slon2(2)-slon2(1))
         171             :          endif
         172             :       endif
         173             :
         174           0 :       if(slon1(im1+1)<slon2(im2+1)) then
         175             : ! case 1:
         176             : !           slon1(im1)                slon1(im1+1)                  slon1(2)    (note: slon1(im1+1) = slon1(1))
         177             : !              |-------------------------|.............................|
         178             : !                   |-------------------------------|
         179             : !               slon2(im2)                        slon2(im2+1) <--- end point
         180           0 :          if(use_flight_distance) then
         181           0 :             weight_x(im2,1) = weight_x(im2,1)+(slon2(1)-slon1(1))/(slon1(2)-slon1(1))
         182             :          else
         183           0 :             weight_x(im2,1) = weight_x(im2,1)+(slon2(1)-slon1(1))/(slon2(2)-slon2(1))
         184             :          endif
         185             :       endif
         186             :
         187             :
         188             :
         189           0 :       do j2=1,jm2
         190             : ! target grid north-south boundaries
         191           0 :          y2_south=slat2(j2)
         192           0 :          y2_north=slat2(j2+1)
         193             :
         194           0 :          do j1=1,jm1
         195             :
         196             : ! source grid north-south boundaries
         197           0 :             y1_south=slat1(j1)
         198           0 :             y1_north=slat1(j1+1)
         199             :
         200             : ! check if there is any overlap between the source grid and the target grid
         201             : ! if no overlap, then weighting is zero
         202             : ! there are three scenarios overlaps can take place
         203             : ! note: there is Guassian weight to consider in the meridional direction!
         204             :
         205           0 :             if( (y1_south>=y2_south).and.(y1_north<=y2_north) ) then
         206             : ! case 1:
         207             : !                y1_south             y1_north
         208             : !                  |-------------------|
         209             : !            |---------------------------------|
         210             : !          y2_south                           y2_north
         211           0 :                 if(use_flight_distance) then
         212           0 :                    weight_y(j2,j1) =  1.0_r8
         213             :                 else
         214           0 :                    weight_y(j2,j1) =  gw1(j1)/gw2(j2)
         215             :                 endif
         216           0 :             elseif ( (y1_south>=y2_south).and.(y1_south<y2_north) ) then
         217             : ! case 2:
         218             : !                y1_south                          y1_north
         219             : !                  |--------------------------------|
         220             : !            |---------------------------------|
         221             : !          y2_south                           y2_north
         222           0 :                 if(use_flight_distance) then
         223           0 :                    weight_y(j2,j1) = (y2_north-y1_south)/(y1_north-y1_south)
         224             :                 else
         225           0 :                    weight_y(j2,j1) = (y2_north-y1_south)/(y1_north-y1_south)*gw1(j1)/gw2(j2)
         226             :                 endif
         227           0 :             elseif ( (y1_north>y2_south).and.(y1_north<=y2_north) ) then
         228             : ! case 3:
         229             : !       y1_south                          y1_north
         230             : !         |--------------------------------|
         231             : !                |---------------------------------|
         232             : !              y2_south                           y2_north
         233           0 :                 if(use_flight_distance) then
         234           0 :                    weight_y(j2,j1) = (y1_north-y2_south)/(y1_north-y1_south)
         235             :                 else
         236           0 :                    weight_y(j2,j1) = (y1_north-y2_south)/(y1_north-y1_south)*gw1(j1)/gw2(j2)
         237             :                 endif
         238           0 :             elseif ( (y1_north>y2_north).and.(y1_south<y2_south) ) then
         239             : ! case 4:
         240             : !       y1_south                          y1_north
         241             : !         |--------------------------------|
         242             : !                |---------------------|
         243             : !              y2_south             y2_north
         244           0 :                 if(use_flight_distance) then
         245           0 :                    weight_y(j2,j1) = 1._r8
         246             :                 else
         247           0 :                    weight_y(j2,j1) = gw1(j1)/gw2(j2)
         248             :                 endif
         249             :             endif
         250             :
         251             :           enddo
         252             :         enddo
         253             :
         254           0 :   end subroutine xy_interp_init
         255             :
         256           0 :   subroutine xy_interp(im1,jm1,km1,im2,jm2,pcols,ncols,weight_x,weight_y,var_src,var_trg,lons,lats,count_x,count_y,index_x,index_y)
         257             : !-------------------------------------------------------------------------------------------------------------
         258             : ! This program interpolates var_src(im1,jm1,km1) to var_trg(im2,jm2,km1) based on weighting functions weight_x & weight_y.
         259             : !-------------------------------------------------------------------------------------------------------------
         260             :   implicit none
         261             :   integer,  intent(in)  :: im1   ! source number of longitudes
         262             :   integer,  intent(in)  :: jm1   ! source number of latitudes
         263             :   integer,  intent(in)  :: km1   ! source/target number of levels
         264             :   integer,  intent(in)  :: im2   ! target number of longitudes
         265             :   integer,  intent(in)  :: jm2   ! target number of latitudes
         266             :   integer,  intent(in)  :: pcols
         267             :   integer,  intent(in)  :: ncols
         268             :   real(r8), intent(in)  :: weight_x(im2,im1), weight_y(jm2,jm1)
         269             :   real(r8), intent(in)  :: var_src(im1,jm1,km1)
         270             :   integer,  intent(in)  :: lons(pcols), lats(pcols)
         271             :   integer,  intent(in)  :: count_x(im2), count_y(jm2)
         272             :   integer,  intent(in)  :: index_x(im2,im1), index_y(jm2,jm1)
         273             :   real(r8), intent(out) :: var_trg(pcols,km1)
         274             :   integer  :: n, i1, j1, k1, i2, j2, ii, jj
         275             :   real(r8) :: sum_x
         276             :
         277           0 :   var_trg(:,:) = 0.0_r8
         278             :
         279             :
         280           0 :   do k1=1,km1
         281           0 :      do n=1,ncols
         282             : ! interpolate in x
         283           0 :         do jj=1,count_y(lats(n))
         284           0 :            sum_x = 0.0_r8
         285           0 :            do ii=1,count_x(lons(n))
         286           0 :               sum_x = sum_x + var_src(index_x(lons(n),ii),index_y(lats(n),jj),k1)* &
         287           0 :                              weight_x(lons(n),index_x(lons(n),ii))
         288             :            enddo
         289           0 :            var_trg(n,k1) = var_trg(n,k1)+sum_x*weight_y(lats(n),index_y(lats(n),jj))
         290             :         enddo
         291             :      enddo
         292             :   enddo
         293             :
         294           0 :   end subroutine xy_interp
         295             :
         296             :
         297             : end module horizontal_interpolate

Generated by: LCOV version 1.14