FMS  2024.03
Flexible Modeling System
grid2.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 grid2_mod grid2_mod
20 !> @ingroup mosaic2
21 !> @brief Routines for grid calculations, using @ref fms2_io
22 
23 !> @addtogroup grid2_mod
24 !> @{
25 module grid2_mod
26 
27 use mpp_mod, only : mpp_root_pe, mpp_error, uppercase, lowercase, fatal, note
28 use constants_mod, only : pi, radius
29 use fms2_io_mod, only : get_global_attribute, read_data, global_att_exists, &
30  variable_exists, file_exists, open_file, close_file, get_variable_size, &
31  fmsnetcdffile_t
32 use fms_string_utils_mod, only: string
35 
36 ! the following two use statement are only needed for define_cube_mosaic
37 use mpp_domains_mod, only : domain2d, mpp_define_mosaic, mpp_get_compute_domain, &
39 use mosaic2_mod, only : get_mosaic_ncontacts, get_mosaic_contact
40 use platform_mod
41 
42 implicit none;private
43 
44 ! ==== public interfaces =====================================================
45 ! grid dimension inquiry subroutines
46 public :: get_great_circle_algorithm ! returns great_circle_algorithm
47 public :: get_grid_ntiles ! returns number of tiles
48 public :: get_grid_size ! returns horizontal sizes of the grid
49 ! grid geometry inquiry subroutines
50 public :: get_grid_cell_centers
51 public :: get_grid_cell_vertices
52 ! grid area inquiry subroutines
53 public :: get_grid_cell_area
54 public :: get_grid_comp_area
55 ! decompose cubed sphere domains -- probably does not belong here, but it should
56 ! be in some place available for component models
57 public :: define_cube_mosaic
58 public :: grid_init
59 public :: grid_end
60 ! ==== end of public interfaces ==============================================
61 
62 !> Gets the size of the grid for one or all tiles
63 !> @ingroup grid2_mod
64 interface get_grid_size
65  module procedure get_grid_size_for_all_tiles
66  module procedure get_grid_size_for_one_tile
67 end interface
68 
69 !> Gets arrays of global grid cell boundaries for given model component and
70 !! mosaic tile number
71 !> @ingroup grid2_mod
73  module procedure get_grid_cell_vertices_1d_r4
74  module procedure get_grid_cell_vertices_1d_r8
75  module procedure get_grid_cell_vertices_2d_r4
76  module procedure get_grid_cell_vertices_2d_r8
77  module procedure get_grid_cell_vertices_ug_r4
78  module procedure get_grid_cell_vertices_ug_r8
79 end interface
80 
81 !> Gets grid cell centers
82 !> @ingroup grid2_mod
84  module procedure get_grid_cell_centers_1d_r4
85  module procedure get_grid_cell_centers_1d_r8
86  module procedure get_grid_cell_centers_2d_r4
87  module procedure get_grid_cell_centers_2d_r8
88  module procedure get_grid_cell_centers_ug_r4
89  module procedure get_grid_cell_centers_ug_r8
90 end interface
91 
92 !> Finds area of a grid cell
93 !> @ingroup grid2_mod
95  module procedure get_grid_cell_area_sg_r4
96  module procedure get_grid_cell_area_sg_r8
97  module procedure get_grid_cell_area_ug_r4
98  module procedure get_grid_cell_area_ug_r8
99 end interface get_grid_cell_area
100 
101 !> Gets the area of a given component per grid cell
102 !> @ingroup grid2_mod
104  module procedure get_grid_comp_area_sg_r4
105  module procedure get_grid_comp_area_sg_r8
106  module procedure get_grid_comp_area_ug_r4
107  module procedure get_grid_comp_area_ug_r8
108 end interface get_grid_comp_area
109 
110 !> @addtogroup grid2_mod
111 !> @{
112 ! ==== module constants ======================================================
113 character(len=*), parameter :: &
114  module_name = 'grid2_mod'
115 
116 ! Include variable "version" to be written to log file.
117 #include<file_version.h>
118 
119 character(len=*), parameter :: &
120  grid_dir = 'INPUT/', & !< root directory for all grid files
121  grid_file = 'INPUT/grid_spec.nc' !< name of the grid spec file
122 
123 integer, parameter :: &
124  max_name = 256, & !< max length of the variable names
125  version_geolon_t = 0, & !< indicates gelon_t variable is present in grid_file
126  version_x_t = 1, & !< indicates x_t variable is present in grid_file
127  version_ocn_mosaic_file = 2, & !< indicates ocn_mosaic_file variable is present in grid_file
128  version_gridfiles = 3 !< indicates gridfiles variable is present in grid_file
129 
130 integer, parameter :: bufsize = 1048576 !< This is used to control memory usage in get_grid_comp_area
131  !! We may change this to a namelist variable is needed.
132 
133 ! ==== module variables ======================================================
134 integer :: grid_version = -1 !< Value to indicate what type of grid file is being read,
135  !! based on which variables are present
136 logical :: great_circle_algorithm = .false.
137 logical :: module_is_initialized = .false.
138 logical :: grid_spec_exists = .true.
139 type(fmsnetcdffile_t) :: gridfileobj
140 type(fmsnetcdffile_t), dimension(3) :: mosaic_fileobj
141 
142 contains
143 
144 !> @brief Initialize the grid2 module
145 subroutine grid_init
146  if (module_is_initialized) return
147  if (.not. file_exists(grid_file)) then
148  module_is_initialized = .true.
149  grid_spec_exists = .false.
150  return
151  endif
152  call open_grid_file(gridfileobj, grid_file)
153  great_circle_algorithm = get_great_circle_algorithm()
154  grid_version = get_grid_version(gridfileobj)
157  module_is_initialized = .true.
158 end subroutine grid_init
159 
160 !> @brief Shutdown the grid2 module
161 subroutine grid_end
162  if (grid_spec_exists) then
164  call close_file(gridfileobj)
165  endif
166 end subroutine grid_end
167 
168 !> @brief Determine if we are using the great circle algorithm
169 !! @return Logical flag describing if we are using the great circlealgorithm
171  character(len=128) :: attvalue
172  logical :: get_great_circle_algorithm
173 
175  if (.not. grid_spec_exists) return
176  if (global_att_exists(gridfileobj, "great_circle_algorithm")) then
177  call get_global_attribute(gridfileobj, "great_circle_algorithm", attvalue)
178  if(trim(attvalue) == "TRUE") then
180  else if(trim(attvalue) .NE. "FALSE") then
181  call mpp_error(fatal, module_name//&
182  '/get_great_circle_algorithm value of global attribute "great_circle_algorthm" in file'// &
183  trim(grid_file)//' should be TRUE or FALSE')
184  endif
185  endif
186 end function get_great_circle_algorithm
187 
188 !> @brief Open a grid file
189 subroutine open_grid_file(myfileobj, myfilename)
190  type(fmsnetcdffile_t), intent(out) :: myfileobj !< File object of grid file
191  character(len=*), intent(in) :: myfilename!< Name of the grid file
192  if(.not. open_file(myfileobj, myfilename, 'read')) then
193  call mpp_error(fatal, 'grid2_mod(open_grid_file):Error in opening file '//trim(myfilename))
194  endif
195 end subroutine open_grid_file
196 
197 !> @brief Open a mosaic file
198 subroutine open_mosaic_file(mymosaicfileobj, component)
199  type(fmsnetcdffile_t), intent(out) :: mymosaicfileobj !< File object returned
200  character(len=3), intent(in) :: component !< Component (atm, lnd, etc.)
201 
202  character(len=FMS_PATH_LEN) :: mosaicfilename
203  if (.not. grid_spec_exists) then
204  call mpp_error(fatal, 'grid2_mod(open_mosaic_file): grid_spec does not exist')
205  end if
206  call read_data(gridfileobj,trim(lowercase(component))//'_mosaic_file', mosaicfilename)
207  call open_grid_file(mymosaicfileobj, grid_dir//trim(mosaicfilename))
208 end subroutine open_mosaic_file
209 
210 !> @brief Read a tile file name from a netcdf file
211 !! @return Name of the file as a string
212 function read_file_name(thisfileobj, filevar, level)
213  type(fmsnetcdffile_t), intent(in) :: thisfileobj !< File object of file
214  character(len=*), intent(in) :: filevar!< Variable containing file names
215  integer, intent(in) :: level !< Level of tile file
216  integer, dimension(2) :: file_list_size
217  character(len=FMS_PATH_LEN) :: read_file_name
218  character(len=FMS_PATH_LEN), dimension(:), allocatable :: file_names
219 
220  call get_variable_size(thisfileobj, filevar, file_list_size)
221  allocate(file_names(file_list_size(2)))
222  call read_data(thisfileobj, filevar, file_names)
223  read_file_name = file_names(level)
224  deallocate(file_names)
225 end function read_file_name
226 
227 !> @brief Get the grid version from a file object
228 !! @return An integer representation of the grid version
229 function get_grid_version(fileobj)
230  type(fmsnetcdffile_t), intent(in) :: fileobj !< File object of grid file
231  integer :: get_grid_version
232 
233  if(grid_version<0) then
234  if(variable_exists(fileobj, 'geolon_t')) then
236  else if(variable_exists(fileobj, 'x_T')) then
238  else if(variable_exists(fileobj, 'ocn_mosaic_file') ) then
240  else if(variable_exists(fileobj, 'gridfiles') ) then
242  else
243  call mpp_error(fatal, module_name//'/get_grid_version Can''t determine the version of the grid spec:'// &
244  & ' none of "x_T", "geolon_t", or "ocn_mosaic_file" exist in file "'//trim(grid_file)//'"')
245  endif
246  endif
247 end function get_grid_version
248 
249 !> @brief Assign the component mosaic files if grid_spec is Version 3
251  if (.not. grid_spec_exists) then
252  call mpp_error(fatal, 'grid2_mod(assign_component_mosaics): grid_spec does not exist')
253  end if
254  mosaic_fileobj(1) = gridfileobj
255  mosaic_fileobj(2) = gridfileobj
256  mosaic_fileobj(3) = gridfileobj
257 end subroutine assign_component_mosaics
258 
259 !> @brief Open the component mosaic files for atm, lnd, and ocn
261  if (.not. grid_spec_exists) then
262  call mpp_error(fatal, 'grid2_mod(open_component_mosaics): grid_spec does not exist')
263  end if
264  if (variable_exists(gridfileobj, 'atm_mosaic_file')) call open_mosaic_file(mosaic_fileobj(1), 'atm')
265  if (variable_exists(gridfileobj, 'ocn_mosaic_file')) call open_mosaic_file(mosaic_fileobj(2), 'ocn')
266  if (variable_exists(gridfileobj, 'lnd_mosaic_file')) call open_mosaic_file(mosaic_fileobj(3), 'lnd')
267 end subroutine open_component_mosaics
268 
269 !> @brief Close the component mosaic files for atm, lnd, and ocn
271  if (.not. grid_spec_exists) then
272  call mpp_error(fatal, 'grid2_mod(close_component_mosaics): grid_spec does not exist')
273  end if
274  if (variable_exists(gridfileobj, 'atm_mosaic_file')) call close_file(mosaic_fileobj(1))
275  if (variable_exists(gridfileobj, 'ocn_mosaic_file')) call close_file(mosaic_fileobj(2))
276  if (variable_exists(gridfileobj, 'lnd_mosaic_file')) call close_file(mosaic_fileobj(3))
277 end subroutine close_component_mosaics
278 
279 !> @brief Get the component number of a model component (atm, lnd, ocn)
280 !! @return Integer component number
281 function get_component_number(component)
282  character(len=*), intent(in) :: component !< Component model (atm, lnd, ocn)
283  integer :: get_component_number
284  select case(lowercase(component))
285  case('atm')
287  case('ocn')
289  case('lnd')
291  end select
292 end function get_component_number
293 
294 !> @brief returns number of tiles for a given component
295 subroutine get_grid_ntiles(component,ntiles)
296  character(len=*) :: component !< Component model (atm, lnd, ocn)
297  integer, intent(out) :: ntiles !< Number of tiles
298 
299  select case (grid_version)
301  ntiles = 1
303  ntiles = get_mosaic_ntiles(mosaic_fileobj(get_component_number(trim(component))))
304  end select
305 end subroutine get_grid_ntiles
306 
307 !> @brief returns size of the grid for each of the tiles
308 subroutine get_grid_size_for_all_tiles(component,nx,ny)
309  character(len=*) :: component !< Component model (atm, lnd, ocn)
310  integer, intent(inout) :: nx(:),ny(:) !< Grid size in x and y
311 
312  ! local vars
313  integer :: siz(2) ! for the size of external fields
314  character(len=MAX_NAME) :: varname1
315 
316  varname1 = 'AREA_'//trim(uppercase(component))
317 
318  select case (grid_version)
320  if (.not. grid_spec_exists) then
321  call mpp_error(fatal, 'grid2_mod(get_grid_size_for_all_tiles): grid_spec does not exist')
322  end if
323  call get_variable_size(gridfileobj, varname1, siz)
324  nx(1) = siz(1); ny(1)=siz(2)
325  case(version_ocn_mosaic_file, version_gridfiles) ! mosaic file
326  call get_mosaic_grid_sizes(mosaic_fileobj(get_component_number(trim(component))),nx,ny)
327  end select
328 end subroutine get_grid_size_for_all_tiles
329 
330 !> @brief returns size of the grid for one of the tiles
331 subroutine get_grid_size_for_one_tile(component,tile,nx,ny)
332  character(len=*) :: component !< Component model (atm, lnd, ocn)
333  integer, intent(in) :: tile !< Tile number
334  integer, intent(inout) :: nx,ny !< Grid size in x and y
335 
336  ! local vars
337  integer, allocatable :: nnx(:), nny(:)
338  integer :: ntiles
339 
340  call get_grid_ntiles(component, ntiles)
341  if(tile>0.and.tile<=ntiles) then
342  allocate(nnx(ntiles),nny(ntiles))
343  call get_grid_size_for_all_tiles(component,nnx,nny)
344  nx = nnx(tile); ny = nny(tile)
345  deallocate(nnx,nny)
346  else
347  call mpp_error(fatal, 'get_grid_size'//&
348  'requested tile index '//trim(string(tile))//' is out of bounds (1:'//trim(string(ntiles))//')')
349  endif
350 end subroutine get_grid_size_for_one_tile
351 
352 !> @brief given a model component, a layout, and (optionally) a halo size, returns a
353 !! domain for current processor
354 subroutine define_cube_mosaic(component, domain, layout, halo, maskmap)
355  character(len=*) , intent(in) :: component !< Component model (atm, lnd, ocn)
356  type(domain2d) , intent(inout) :: domain !< Domain
357  integer , intent(in) :: layout(2) !< Layout
358  integer, optional, intent(in) :: halo !< Halo
359  logical, optional, intent(in) :: maskmap(:,:,:) !< Maskmap
360 
361  ! ---- local vars
362  integer :: ntiles ! number of tiles
363  integer :: ncontacts ! number of contacts between mosaic tiles
364  integer :: n
365  integer :: ng, pe_pos, npes ! halo size
366  integer, allocatable :: nlon(:), nlat(:), global_indices(:,:)
367  integer, allocatable :: pe_start(:), pe_end(:), layout_2d(:,:)
368  integer, allocatable :: tile1(:),tile2(:)
369  integer, allocatable :: is1(:),ie1(:),js1(:),je1(:)
370  integer, allocatable :: is2(:),ie2(:),js2(:),je2(:)
371 
372  call get_grid_ntiles(component,ntiles)
373  allocate(nlon(ntiles), nlat(ntiles))
374  allocate(global_indices(4,ntiles))
375  allocate(pe_start(ntiles),pe_end(ntiles))
376  allocate(layout_2d(2,ntiles))
377  call get_grid_size(component,nlon,nlat)
378 
379  pe_pos = mpp_root_pe()
380  do n = 1, ntiles
381  global_indices(:,n) = (/ 1, nlon(n), 1, nlat(n) /)
382  layout_2d(:,n) = layout
383  if(present(maskmap)) then
384  npes = count(maskmap(:,:,n))
385  else
386  npes = layout(1)*layout(2)
387  endif
388  pe_start(n) = pe_pos
389  pe_end(n) = pe_pos + npes - 1
390  pe_pos = pe_end(n) + 1
391  enddo
392 
393  ! get the contact information from mosaic file
394  ncontacts = get_mosaic_ncontacts(mosaic_fileobj(get_component_number(trim(component))))
395  allocate(tile1(ncontacts),tile2(ncontacts))
396  allocate(is1(ncontacts),ie1(ncontacts),js1(ncontacts),je1(ncontacts))
397  allocate(is2(ncontacts),ie2(ncontacts),js2(ncontacts),je2(ncontacts))
398  call get_mosaic_contact(mosaic_fileobj(get_component_number(trim(component))), tile1, tile2, &
399  is1, ie1, js1, je1, is2, ie2, js2, je2)
400 
401  ng = 0
402  if(present(halo)) ng = halo
403  ! create the domain2d variable
404  call mpp_define_mosaic ( global_indices, layout_2d, domain, &
405  ntiles, ncontacts, tile1, tile2, &
406  is1, ie1, js1, je1, &
407  is2, ie2, js2, je2, &
408  pe_start=pe_start, pe_end=pe_end, symmetry=.true., &
409  shalo = ng, nhalo = ng, whalo = ng, ehalo = ng, &
410  maskmap = maskmap, &
411  name = trim(component)//'Cubic-Sphere Grid' )
412 
413  deallocate(nlon,nlat,global_indices,pe_start,pe_end,layout_2d)
414  deallocate(tile1,tile2)
415  deallocate(is1,ie1,js1,je1)
416  deallocate(is2,ie2,js2,je2)
417 end subroutine define_cube_mosaic
418 
419 #include "grid2_r4.fh"
420 #include "grid2_r8.fh"
421 
422 end module grid2_mod
423 !> @}
424 ! 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
character(:) function, allocatable, public string(v, fmt)
Converts a number or a Boolean value to a string.
integer grid_version
Value to indicate what type of grid file is being read, based on which variables are present.
Definition: grid2.F90:134
integer, parameter version_gridfiles
indicates gridfiles variable is present in grid_file
Definition: grid2.F90:123
subroutine, public grid_end
Shutdown the grid2 module.
Definition: grid2.F90:162
subroutine, public grid_init
Initialize the grid2 module.
Definition: grid2.F90:146
subroutine open_mosaic_file(mymosaicfileobj, component)
Open a mosaic file.
Definition: grid2.F90:199
integer function get_component_number(component)
Get the component number of a model component (atm, lnd, ocn)
Definition: grid2.F90:282
integer, parameter version_ocn_mosaic_file
indicates ocn_mosaic_file variable is present in grid_file
Definition: grid2.F90:123
integer, parameter version_geolon_t
indicates gelon_t variable is present in grid_file
Definition: grid2.F90:123
character(len=fms_path_len) function read_file_name(thisfileobj, filevar, level)
Read a tile file name from a netcdf file.
Definition: grid2.F90:213
subroutine open_component_mosaics
Open the component mosaic files for atm, lnd, and ocn.
Definition: grid2.F90:261
subroutine, public get_grid_ntiles(component, ntiles)
returns number of tiles for a given component
Definition: grid2.F90:296
subroutine assign_component_mosaics
Assign the component mosaic files if grid_spec is Version 3.
Definition: grid2.F90:251
character(len= *), parameter grid_dir
root directory for all grid files
Definition: grid2.F90:119
integer, parameter version_x_t
indicates x_t variable is present in grid_file
Definition: grid2.F90:123
subroutine open_grid_file(myfileobj, myfilename)
Open a grid file.
Definition: grid2.F90:190
subroutine close_component_mosaics
Close the component mosaic files for atm, lnd, and ocn.
Definition: grid2.F90:271
integer, parameter bufsize
This is used to control memory usage in get_grid_comp_area We may change this to a namelist variable ...
Definition: grid2.F90:130
subroutine get_grid_size_for_one_tile(component, tile, nx, ny)
returns size of the grid for one of the tiles
Definition: grid2.F90:332
integer, parameter max_name
max length of the variable names
Definition: grid2.F90:123
character(len= *), parameter grid_file
name of the grid spec file
Definition: grid2.F90:119
integer function get_grid_version(fileobj)
Get the grid version from a file object.
Definition: grid2.F90:230
subroutine, public define_cube_mosaic(component, domain, layout, halo, maskmap)
given a model component, a layout, and (optionally) a halo size, returns a domain for current process...
Definition: grid2.F90:355
logical function, public get_great_circle_algorithm()
Determine if we are using the great circle algorithm.
Definition: grid2.F90:171
subroutine get_grid_size_for_all_tiles(component, nx, ny)
returns size of the grid for each of the tiles
Definition: grid2.F90:309
Finds area of a grid cell.
Definition: grid2.F90:94
Gets grid cell centers.
Definition: grid2.F90:83
Gets arrays of global grid cell boundaries for given model component and mosaic tile number.
Definition: grid2.F90:72
Gets the area of a given component per grid cell.
Definition: grid2.F90:103
Gets the size of the grid for one or all tiles.
Definition: grid2.F90:64
integer function, public get_mosaic_xgrid_size(fileobj)
return exchange grid size of mosaic xgrid file.
Definition: mosaic2.F90:119
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_ntiles(fileobj)
Get number of tiles in the mosaic_file.
Definition: mosaic2.F90:135
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 mpp_define_mosaic(global_indices, layout, domain, num_tile, num_contact, tile1, tile2, istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, pe_start, pe_end, pelist, whalo, ehalo, shalo, nhalo, xextent, yextent, maskmap, name, memory_size, symmetry, xflags, yflags, tile_id)
Defines a domain for mosaic tile grids.
These routines retrieve the axis specifications associated with the compute domains....
These routines retrieve the axis specifications associated with the global domains....
Passes data from a structured grid to an unstructured grid Example usage:
The domain2D type contains all the necessary information to define the global, compute and data domai...
Domain information for managing data on unstructured grids.
Error handler.
Definition: mpp.F90:382