FMS  2025.03
Flexible Modeling System
mosaic2.inc
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 
20 !> @file
21 
22 !> @brief Get exchange grid information from mosaic xgrid file.
23 !> Example usage:
24 !!
25 !! call get_mosaic_xgrid(fileobj, nxgrid, i1, j1, i2, j2, area)
26 !!
27  subroutine get_mosaic_xgrid_(fileobj, i1, j1, i2, j2, area, ibegin, iend)
28  type(FmsNetcdfFile_t), intent(in) :: fileobj !> The file that contains exchange grid information.
29  integer, intent(inout) :: i1(:), j1(:), i2(:), j2(:) !> i and j indices for grids 1 and 2
30  real(kind=fms_mos_kind_), intent(inout) :: area(:) !> area of the exchange grid. The area is scaled to
31  !! represent unit earth area
32  integer, optional, intent(in) :: ibegin, iend
33 
34  integer :: start(4), nread(4), istart
35  real(kind=fms_mos_kind_), dimension(2, size(i1(:))) :: tile1_cell, tile2_cell
36  integer :: nxgrid, n
37  real(kind=r8_kind) :: garea
38  real(kind=r8_kind) :: get_global_area
39 
40  garea = get_global_area() !< get_global_area returns a r8_kind
41 
42  ! When start and nread present, make sure nread(1) is the same as the size of the data
43  if(present(ibegin) .and. present(iend)) then
44  istart = ibegin
45  nxgrid = iend - ibegin + 1
46  if(nxgrid .NE. size(i1(:))) call mpp_error(fatal, .NE."get_mosaic_xgrid: nxgrid size(i1(:))")
47  if(nxgrid .NE. size(j1(:))) call mpp_error(fatal, .NE."get_mosaic_xgrid: nxgrid size(j1(:))")
48  if(nxgrid .NE. size(i2(:))) call mpp_error(fatal, .NE."get_mosaic_xgrid: nxgrid size(i2(:))")
49  if(nxgrid .NE. size(j2(:))) call mpp_error(fatal, .NE."get_mosaic_xgrid: nxgrid size(j2(:))")
50  if(nxgrid .NE. size(area(:))) call mpp_error(fatal, .NE."get_mosaic_xgrid: nxgrid size(area(:))")
51  else
52  istart = 1
53  nxgrid = size(i1(:))
54  endif
55 
56  start = 1; nread = 1
57  start(1) = istart; nread(1) = nxgrid
58 
59  call read_data(fileobj, 'xgrid_area', area, corner=start, edge_lengths=nread)
60 
61  start = 1; nread = 1
62  nread(1) = 2
63  start(2) = istart; nread(2) = nxgrid
64 
65  call read_data(fileobj, 'tile1_cell', tile1_cell, corner=start, edge_lengths=nread)
66  call read_data(fileobj, 'tile2_cell', tile2_cell, corner=start, edge_lengths=nread)
67 
68  do n = 1, nxgrid
69  i1(n) = int(tile1_cell(1,n))
70  j1(n) = int(tile1_cell(2,n))
71  i2(n) = int(tile2_cell(1,n))
72  j2(n) = int(tile2_cell(2,n))
73  area(n) = real( real(area(n),r8_kind)/garea, fms_mos_kind_ )
74  end do
75 
76  return
77 
78  end subroutine get_mosaic_xgrid_
79  !###############################################################################
80  !> @brief Calculate grid cell area.
81  !> Calculate the grid cell area. The purpose of this routine is to make
82  !! sure the consistency between model grid area and exchange grid area.
83  !> @param lon geographical longitude of grid cell vertices.
84  !> @param lat geographical latitude of grid cell vertices.
85  !> @param[inout] area grid cell area.
86  !> <br>Example usage:
87  !! call calc_mosaic_grid_area(lon, lat, area)
88  subroutine calc_mosaic_grid_area_(lon, lat, area)
89  real(kind=fms_mos_kind_), dimension(:,:), intent(in) :: lon
90  real(kind=fms_mos_kind_), dimension(:,:), intent(in) :: lat
91  real(kind=fms_mos_kind_), dimension(:,:), intent(out) :: area
92  integer :: nlon, nlat
93 
94  real(r8_kind) :: area_r8(size(area,1),size(area,2))
95 
96  nlon = size(area,1)
97  nlat = size(area,2)
98  ! make sure size of lon, lat and area are consitency
99  if( size(lon,1) .NE. nlon+1 .OR. size(lat,1) .NE. nlon+1 ) &
100  call mpp_error(fatal, "mosaic_mod: size(lon,1) and size(lat,1) should equal to size(area,1)+1")
101  if( size(lon,2) .NE. nlat+1 .OR. size(lat,2) .NE. nlat+1 ) &
102  call mpp_error(fatal, "mosaic_mod: size(lon,2) and size(lat,2) should equal to size(area,2)+1")
103 
104  ! get_grid_area only accepts double precision data
105  call get_grid_area( nlon, nlat, real(lon,r8_kind), real(lat,r8_kind), area_r8)
106 
107  area=real(area_r8,fms_mos_kind_)
108 
109  end subroutine calc_mosaic_grid_area_
110  !###############################################################################
111  !> @brief Calculate grid cell area using great cirlce algorithm
112  !> Calculate the grid cell area. The purpose of this routine is to make
113  !! sure the consistency between model grid area and exchange grid area.
114  !> @param lon geographical longitude of grid cell vertices.
115  !> @param lat geographical latitude of grid cell vertices.
116  !> @param[inout] area grid cell area.
117  !> <br>Example usage:
118  !! call calc_mosaic_grid_great_circle_area(lon, lat, area)
119  subroutine calc_mosaic_grid_great_circle_area_(lon, lat, area)
120  real(kind=fms_mos_kind_), dimension(:,:), intent(in) :: lon
121  real(kind=fms_mos_kind_), dimension(:,:), intent(in) :: lat
122  real(kind=fms_mos_kind_), dimension(:,:), intent(inout) :: area
123  integer :: nlon, nlat
124 
125  real(r8_kind) :: area_r8(size(area,1),size(area,2))
126 
127  nlon = size(area,1)
128  nlat = size(area,2)
129  ! make sure size of lon, lat and area are consitency
130  if( size(lon,1) .NE. nlon+1 .OR. size(lat,1) .NE. nlon+1 ) &
131  call mpp_error(fatal, "mosaic_mod: size(lon,1) and size(lat,1) should equal to size(area,1)+1")
132  if( size(lon,2) .NE. nlat+1 .OR. size(lat,2) .NE. nlat+1 ) &
133  call mpp_error(fatal, "mosaic_mod: size(lon,2) and size(lat,2) should equal to size(area,2)+1")
134 
135  ! get_grid_great_circle_area only accepts r8_kind arguments
136  call get_grid_great_circle_area( nlon, nlat, real(lon,r8_kind), real(lat,r8_kind), area_r8)
137 
138  area=real(area_r8, fms_mos_kind_)
139 
140  end subroutine calc_mosaic_grid_great_circle_area_
141  !#####################################################################
142  !> This function check if a point (lon1,lat1) is inside a polygon (lon2(:), lat2(:))
143  !! lon1, lat1, lon2, lat2 are in radians.
144  function is_inside_polygon_(lon1, lat1, lon2, lat2 )
145  real(kind=fms_mos_kind_), intent(in) :: lon1, lat1
146  real(kind=fms_mos_kind_), intent(in) :: lon2(:), lat2(:)
147  logical :: IS_INSIDE_POLYGON_
148  integer :: npts, isinside
149  integer :: inside_a_polygon
150 
151  npts = size(lon2(:))
152 
153  !> inside_a_polygon function only accepts r8_kind real variables
154 
155  isinside = inside_a_polygon(real(lon1,r8_kind), real(lat1,r8_kind), npts, real(lon2,r8_kind), real(lat2,r8_kind))
156  if(isinside == 1) then
157  is_inside_polygon_ = .true.
158  else
159  is_inside_polygon_ = .false.
160  endif
161 
162  return
163 
164  end function is_inside_polygon_
165 !> @}