FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
mosaic2.F90
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!> @defgroup mosaic2_mod mosaic2_mod
20!> @ingroup mosaic2
21!> @brief Implements some utility routines to read mosaic information.
22!!
23!> @author Zhi Liang
24!!
25!! Implements some utility routines to read mosaic information.
26!! The information includes number of tiles and contacts in the mosaic,
27!! mosaic grid resolution of each tile, mosaic contact information, mosaic exchange
28!! grid information. Each routine will call a C-version routine to get these information.
29
30!> @addtogroup mosaic2_mod
31!> @{
32module mosaic2_mod
33
34!use fms_mod, only : write_version_number
35
36use mpp_mod, only : mpp_error, fatal, mpp_pe, mpp_root_pe
37use mpp_domains_mod, only : domain2d, mpp_get_current_ntile, mpp_get_tile_id
38use constants_mod, only : pi, radius
39use fms2_io_mod, only : fmsnetcdffile_t, open_file, close_file, get_dimension_size
40use fms2_io_mod, only : read_data, variable_exists
41use platform_mod, only : r4_kind, r8_kind, fms_path_len
42
43implicit none
44private
45
46character(len=*), parameter :: &
47 grid_dir = 'INPUT/' !> root directory for all grid files
48
49integer, parameter :: &
50 MAX_NAME = 256, & !> max length of the variable names
51 x_refine = 2, & !> supergrid size/model grid size in x-direction
52 y_refine = 2 !> supergrid size/model grid size in y-direction
53
54! --- public interface
55
56
57public :: get_mosaic_ntiles
60public :: get_mosaic_contact
62public :: get_mosaic_xgrid
66public :: is_inside_polygon
67
68
70 module procedure get_mosaic_xgrid_r4
71 module procedure get_mosaic_xgrid_r8
72end interface get_mosaic_xgrid
73
75 module procedure calc_mosaic_grid_area_r4
76 module procedure calc_mosaic_grid_area_r8
77end interface calc_mosaic_grid_area
78
80 module procedure calc_mosaic_grid_great_circle_area_r4
81 module procedure calc_mosaic_grid_great_circle_area_r8
83
85 module procedure is_inside_polygon_r4
86 module procedure is_inside_polygon_r8
87end interface is_inside_polygon
88
89
90logical :: module_is_initialized = .true.
91! Include variable "version" to be written to log file.
92#include<file_version.h>
93
94contains
95
96!#######################################################################
97
98!> @brief Initialize the mosaic_mod.
99!> Initialization routine for the mosaic module. It writes the
100!! version information to the log file.
101!! <br>Example usage:
102!! call mosaic_init ( )
103subroutine mosaic_init()
104
105 if (module_is_initialized) return
106 module_is_initialized = .true.
107
108!--------- write version number and namelist ------------------
109! call write_version_number("MOSAIC_MOD", version)
110
111end subroutine mosaic_init
112
113!#######################################################################
114!> @brief return exchange grid size of mosaic xgrid file.
115!!
116!> <br>Example usage:
117!! nxgrid = get_mosaic_xgrid_size(xgrid_file)
118 function get_mosaic_xgrid_size(fileobj)
119 type(fmsnetcdffile_t), intent(in) :: fileobj !> File that contains exchange grid information.
120 integer :: get_mosaic_xgrid_size
121
122 call get_dimension_size(fileobj, "ncells", get_mosaic_xgrid_size)
123
124 return
125
126 end function get_mosaic_xgrid_size
127 !###############################################################################
128 !> Get number of tiles in the mosaic_file.
129 !> @param fileobj mosaic file object
130 !> @return Number of tiles in given file
131 !> <br>Example usage:
132 !! ntiles = get_mosaic_ntiles( mosaic_file)
133 !!
134 function get_mosaic_ntiles(fileobj)
135 type(fmsnetcdffile_t), intent(in) :: fileobj
136 integer :: get_mosaic_ntiles
137
138 call get_dimension_size(fileobj, "ntiles", get_mosaic_ntiles)
139
140 return
141
142 end function get_mosaic_ntiles
143
144 !###############################################################################
145 !> Get number of contacts in the mosaic_file.
146 !> @param fileobj mosaic file object
147 !> @return number of contacts in a given file
148 !> <br>Example usage:
149 !! ntiles = get_mosaic_ncontacts( mosaic_file)
150 function get_mosaic_ncontacts(fileobj)
151 type(fmsnetcdffile_t), intent(in) :: fileobj
152 integer :: get_mosaic_ncontacts
153
154 if(variable_exists(fileobj, "contacts") ) then
155 call get_dimension_size(fileobj, "ncontact", get_mosaic_ncontacts)
156 else
158 endif
159
160 return
161
162 end function get_mosaic_ncontacts
163
164
165 !###############################################################################
166 !> Get grid size of each tile from mosaic_file
167 !> @param fileobj mosaic file object
168 !> @param[inout] nx List of grid size in x-direction of each tile
169 !> @param[inout] ny List of grid size in y-direction of each tile
170 !> <br>Example usage:
171 !! call get_mosaic_grid_sizes(mosaic_file, nx, ny)
172 subroutine get_mosaic_grid_sizes( fileobj, nx, ny)
173 type(fmsnetcdffile_t), intent(in) :: fileobj
174 integer, dimension(:), intent(inout) :: nx, ny
175
176 character(len=FMS_PATH_LEN) :: gridfile
177 integer :: ntiles, n
178 type(fmsnetcdffile_t) :: gridobj
179
180 ntiles = get_mosaic_ntiles(fileobj)
181 if(ntiles .NE. size(nx(:)) .OR. ntiles .NE. size(ny(:)) ) then
182 call mpp_error(fatal, "get_mosaic_grid_sizes: size of nx/ny does not equal to ntiles")
183 endif
184
185 do n = 1, ntiles
186 call read_data(fileobj, 'gridfiles', gridfile, corner=n)
187 gridfile = grid_dir//trim(gridfile)
188
189 if(.not. open_file(gridobj, gridfile, 'read')) then
190 call mpp_error(fatal, 'mosaic_mod(get_mosaic_grid_sizes):Error in opening file '//trim(gridfile))
191 endif
192 call get_dimension_size(gridobj, "nx", nx(n))
193 call get_dimension_size(gridobj, "ny", ny(n))
194 call close_file(gridobj)
195 if(mod(nx(n),x_refine) .NE. 0) call mpp_error(fatal, "get_mosaic_grid_sizes: nx is not divided by x_refine");
196 if(mod(ny(n),y_refine) .NE. 0) call mpp_error(fatal, "get_mosaic_grid_sizes: ny is not divided by y_refine");
197 nx(n) = nx(n)/x_refine;
198 ny(n) = ny(n)/y_refine;
199 enddo
200
201 return
202
203 end subroutine get_mosaic_grid_sizes
204
205 !###############################################################################
206 !> Get contact information from mosaic_file
207 !> <br>Example usage:
208 !! call get_mosaic_contact(mosaic_file, tile1, tile2, istart1, iend1, jstart1, jend1,
209 !! istart2, iend2, jstart2, jend2)
210 !> @param fileobj mosaic file object
211 !> @param[inout] tile1 list of tile numbers in tile 1 of each contact
212 !> @param[inout] tile2 list of tile numbers in tile 2 of each contact
213 !> @param[inout] istart1 list of starting i-index in tile 1 of each contact
214 !> @param[inout] iend1 list of ending i-index in tile 1 of each contact
215 !> @param[inout] jstart1 list of starting j-index in tile 1 of each contact
216 !> @param[inout] jend1 list of ending j-index in tile 1 of each contact
217 !> @param[inout] istart2 list of starting i-index in tile 2 of each contact
218 !> @param[inout] iend2 list of ending i-index in tile 2 of each contact
219 !> @param[inout] jstart2 list of starting j-index in tile 2 of each contact
220 !> @param[inout] jend2 list of ending j-index in tile 2 of each contact
221 subroutine get_mosaic_contact( fileobj, tile1, tile2, istart1, iend1, jstart1, jend1, &
222 istart2, iend2, jstart2, jend2)
223 type(fmsnetcdffile_t), intent(in) :: fileobj
224 integer, dimension(:), intent(inout) :: tile1, tile2
225 integer, dimension(:), intent(inout) :: istart1, iend1, jstart1, jend1
226 integer, dimension(:), intent(inout) :: istart2, iend2, jstart2, jend2
227 character(len=MAX_NAME), allocatable :: gridtiles(:)
228 character(len=MAX_NAME), allocatable :: contacts(:)
229 character(len=MAX_NAME), allocatable :: contacts_index(:)
230 character(len=MAX_NAME) :: strlist(8)
231 integer :: ntiles, n, m, ncontacts, nstr, ios
232 integer :: i1_type, j1_type, i2_type, j2_type
233 logical :: found
234
235 ntiles = get_mosaic_ntiles(fileobj)
236 allocate(gridtiles(ntiles))
237 if(mpp_pe()==mpp_root_pe()) then
238 do n = 1, ntiles
239 do m = 1,max_name
240 gridtiles(n)(m:m) = " "
241 enddo
242 enddo
243 endif
244 call read_data(fileobj, 'gridtiles', gridtiles)
245
246 ncontacts = get_mosaic_ncontacts(fileobj)
247 if(ncontacts>0) then
248 allocate(contacts(ncontacts), contacts_index(ncontacts))
249 if(mpp_pe()==mpp_root_pe()) then
250 do n = 1, ncontacts
251 do m = 1,max_name
252 contacts(n)(m:m) = " "
253 contacts_index(n)(m:m) = " "
254 enddo
255 enddo
256 endif
257 call read_data(fileobj, "contacts", contacts)
258 call read_data(fileobj, "contact_index", contacts_index)
259 endif
260 do n = 1, ncontacts
261 nstr = parse_string(contacts(n), ":", strlist)
262 if(nstr .NE. 4) call mpp_error(fatal, &
263 "mosaic_mod(get_mosaic_contact): number of elements in contact seperated by :/:: should be 4")
264 found = .false.
265 do m = 1, ntiles
266 if(trim(gridtiles(m)) == trim(strlist(2)) ) then !found the tile name
267 found = .true.
268 tile1(n) = m
269 exit
270 endif
271 enddo
272
273 if(.not.found) call mpp_error(fatal, &
274 "mosaic_mod(get_mosaic_contact):the first tile name specified in contact is not found in tile list")
275
276 found = .false.
277 do m = 1, ntiles
278 if(trim(gridtiles(m)) == trim(strlist(4)) ) then !found the tile name
279 found = .true.
280 tile2(n) = m
281 exit
282 endif
283 enddo
284
285 if(.not.found) call mpp_error(fatal, &
286 "mosaic_mod(get_mosaic_contact):the second tile name specified in contact is not found in tile list")
287
288 nstr = parse_string(contacts_index(n), ":,", strlist)
289 if(nstr .NE. 8) then
290 if(mpp_pe()==mpp_root_pe()) then
291 print*, "nstr is ", nstr
292 print*, "contacts is ", contacts_index(n)
293 do m = 1, nstr
294 print*, "strlist is ", trim(strlist(m))
295 enddo
296 endif
297 call mpp_error(fatal, &
298 "mosaic_mod(get_mosaic_contact): number of elements in contact_index seperated by :/, should be 8")
299 endif
300 read(strlist(1), *, iostat=ios) istart1(n)
301 if(ios .NE. 0) call mpp_error(fatal, &
302 "mosaic_mod(get_mosaic_contact): Error in reading istart1")
303 read(strlist(2), *, iostat=ios) iend1(n)
304 if(ios .NE. 0) call mpp_error(fatal, &
305 "mosaic_mod(get_mosaic_contact): Error in reading iend1")
306 read(strlist(3), *, iostat=ios) jstart1(n)
307 if(ios .NE. 0) call mpp_error(fatal, &
308 "mosaic_mod(get_mosaic_contact): Error in reading jstart1")
309 read(strlist(4), *, iostat=ios) jend1(n)
310 if(ios .NE. 0) call mpp_error(fatal, &
311 "mosaic_mod(get_mosaic_contact): Error in reading jend1")
312 read(strlist(5), *, iostat=ios) istart2(n)
313 if(ios .NE. 0) call mpp_error(fatal, &
314 "mosaic_mod(get_mosaic_contact): Error in reading istart2")
315 read(strlist(6), *, iostat=ios) iend2(n)
316 if(ios .NE. 0) call mpp_error(fatal, &
317 "mosaic_mod(get_mosaic_contact): Error in reading iend2")
318 read(strlist(7), *, iostat=ios) jstart2(n)
319 if(ios .NE. 0) call mpp_error(fatal, &
320 "mosaic_mod(get_mosaic_contact): Error in reading jstart2")
321 read(strlist(8), *, iostat=ios) jend2(n)
322 if(ios .NE. 0) call mpp_error(fatal, &
323 "mosaic_mod(get_mosaic_contact): Error in reading jend2")
324
325 i1_type = transfer_to_model_index(istart1(n), iend1(n), x_refine)
326 j1_type = transfer_to_model_index(jstart1(n), jend1(n), y_refine)
327 i2_type = transfer_to_model_index(istart2(n), iend2(n), x_refine)
328 j2_type = transfer_to_model_index(jstart2(n), jend2(n), y_refine)
329
330 if( i1_type == 0 .AND. j1_type == 0 ) call mpp_error(fatal, &
331 "mosaic_mod(get_mosaic_contact): istart1==iend1 and jstart1==jend1")
332 if( i2_type == 0 .AND. j2_type == 0 ) call mpp_error(fatal, &
333 "mosaic_mod(get_mosaic_contact): istart2==iend2 and jstart2==jend2")
334 if( i1_type + j1_type .NE. i2_type + j2_type ) call mpp_error(fatal, &
335 "mosaic_mod(get_mosaic_contact): It is not a line or overlap contact")
336
337 enddo
338
339 deallocate(gridtiles)
340 if(ncontacts>0) deallocate(contacts, contacts_index)
341
342 end subroutine get_mosaic_contact
343
344
345function transfer_to_model_index(istart, iend, refine_ratio)
346 integer, intent(inout) :: istart, iend
347 integer :: refine_ratio
348 integer :: transfer_to_model_index
349 integer :: istart_in, iend_in
350
351 istart_in = istart
352 iend_in = iend
353
354 if( istart_in == iend_in ) then
355 transfer_to_model_index = 0
356 istart = (istart_in + 1)/refine_ratio
357 iend = istart
358 else
359 transfer_to_model_index = 1
360 if( iend_in > istart_in ) then
361 istart = istart_in + 1
362 iend = iend_in
363 else
364 istart = istart_in
365 iend = iend_in + 1
366 endif
367 if( mod(istart, refine_ratio) .NE. 0 .OR. mod(iend,refine_ratio) .NE. 0) call mpp_error(fatal, &
368 "mosaic_mod(transfer_to_model_index): mismatch between refine_ratio and istart/iend")
369 istart = istart/refine_ratio
370 iend = iend/refine_ratio
371
372 endif
373
374 return
375
376end function transfer_to_model_index
377!#####################################################################
378function parse_string(string, set, sval)
379 character(len=*), intent(in) :: string
380 character(len=*), intent(in) :: set
381 character(len=*), intent(out) :: sval(:)
382 integer :: parse_string
383 integer :: nelem, length, first, last
384
385 nelem = size(sval(:))
386 length = len_trim(string)
387
388 first = 1; last = 0
389 parse_string = 0
390
391 do while(first .LE. length)
392 parse_string = parse_string + 1
393 if(parse_string>nelem) then
394 call mpp_error(fatal, "mosaic_mod(parse_string) : number of element is greater than size(sval(:))")
395 endif
396 last = first - 1 + scan(string(first:length), set)
397 if(last == first-1 ) then ! not found, end of string
398 sval(parse_string) = string(first:length)
399 exit
400 else
401 if(last <= first) then
402 call mpp_error(fatal, "mosaic_mod(parse_string) : last <= first")
403 endif
404 sval(parse_string) = string(first:(last-1))
405 first = last + 1
406 ! scan to make sure the next is not the character in the set
407 do while (first == last+1)
408 last = first - 1 + scan(string(first:length), set)
409 if(last == first) then
410 first = first+1
411 else
412 exit
413 endif
414 end do
415 endif
416 enddo
417
418 return
419
420end function parse_string
421
422 !#############################################################################
423 !> Gets the name of a mosaic tile grid file
424 !> @param[out] grid_file name of grid file
425 !> @param fileobj mosaic file object
426 !> @param domain current domain
427 !> @param tile_count optional count of tiles
428subroutine get_mosaic_tile_grid(grid_file, fileobj, domain, tile_count)
429 character(len=*), intent(out) :: grid_file
430 type(fmsnetcdffile_t), intent(in) :: fileobj
431 type(domain2d), intent(in) :: domain
432 integer, intent(in), optional :: tile_count
433 integer :: tile, ntileme
434 integer, dimension(:), allocatable :: tile_id
435 character(len=256), allocatable :: filelist(:)
436 integer :: ntiles
437
438 ntiles = get_mosaic_ntiles(fileobj)
439 allocate(filelist(ntiles))
440 tile = 1
441 if(present(tile_count)) tile = tile_count
442 ntileme = mpp_get_current_ntile(domain)
443 allocate(tile_id(ntileme))
444 tile_id = mpp_get_tile_id(domain)
445 call read_data(fileobj, "gridfiles", filelist)
446 grid_file = 'INPUT/'//trim(filelist(tile_id(tile)))
447 deallocate(tile_id, filelist)
448
449end subroutine get_mosaic_tile_grid
450
451#include "mosaic2_r4.fh"
452#include "mosaic2_r8.fh"
453
454end module mosaic2_mod
455!> @}
456! close documentation grouping
Close a netcdf or domain file opened with open_file or open_virtual_file.
Definition fms2_io.F90:166
Opens a given netcdf or domain file.
Definition fms2_io.F90:122
Read data from a defined field in a file.
Definition fms2_io.F90:292
subroutine, public get_mosaic_tile_grid(grid_file, fileobj, domain, tile_count)
Gets the name of a mosaic tile grid file.
Definition mosaic2.F90:429
integer function, public get_mosaic_ncontacts(fileobj)
Get number of contacts in the mosaic_file.
Definition mosaic2.F90:151
subroutine, public get_mosaic_grid_sizes(fileobj, nx, ny)
Get grid size of each tile from mosaic_file.
Definition mosaic2.F90:173
subroutine, public get_mosaic_contact(fileobj, tile1, tile2, istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2)
Get contact information from mosaic_file Example usage: call get_mosaic_contact(mosaic_file,...
Definition mosaic2.F90:223
integer function, public get_mosaic_xgrid_size(fileobj)
return exchange grid size of mosaic xgrid file.
Definition mosaic2.F90:119
integer function, public get_mosaic_ntiles(fileobj)
Get number of tiles in the mosaic_file.
Definition mosaic2.F90:135
subroutine mosaic_init()
Initialize the mosaic_mod. Initialization routine for the mosaic module. It writes the version inform...
Definition mosaic2.F90:104
integer function, dimension(size(domain%tile_id(:))) mpp_get_tile_id(domain)
Returns the tile_id on current pe.
integer function mpp_get_current_ntile(domain)
Returns number of tile on current pe.
The domain2D type contains all the necessary information to define the global, compute and data domai...
Error handler.
Definition mpp.F90:382