FMS  2026.01.01-dev
Flexible Modeling System
fms_netcdf_unstructured_domain_io.F90
1 !***********************************************************************
2 !* Apache License 2.0
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* Licensed under the Apache License, Version 2.0 (the "License");
7 !* you may not use this file except in compliance with the License.
8 !* You may obtain a copy of the License at
9 !*
10 !* http://www.apache.org/licenses/LICENSE-2.0
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 !* PARTICULAR PURPOSE. See the License for the specific language
16 !* governing permissions and limitations under the License.
17 !***********************************************************************
18 !> @defgroup fms_netcdf_unstructured_domain_io_mod fms_netcdf_unstructured_domain_io_mod
19 !> @ingroup fms2_io
20 !> @brief This module defines the derived type, FmsNetcdfUnstructuredDomainFile_t, and routines
21 !! to handle calls to the netcdf library for data on a domain decomposed unstructured grid.
22 !! See mpp_domains_mod for more information on domain decomposition.
23 !!
24 !! This module is not intended to be used externally. Please use the public interfaces in fms2_io_mod
25 !! for IO operations.
26 !!
27 module fms_netcdf_unstructured_domain_io_mod
28 use netcdf
29 use mpp_domains_mod
30 use fms_io_utils_mod
31 use netcdf_io_mod
32 use platform_mod
33 implicit none
34 private
35 
36 !> @brief Type to represent a netCDF file when on a domain decomposed unstructured grid.
37 !! Used to do distributed I/O across ranks, as determined by the io_layout. The io_layout
38 !! is a 1D array (nx_pe,ny_pe) of size 2 set via mpp_set_io_domain
39 !! and determines how many PEs will be performing IO operations within a given
40 !! domain decompositon. The total number of writing PEs is nx_pe * ny_pe.
41 !!
42 !! For example, if domain's layout was (4,4) so 16 PEs total,
43 !! then a io_layout of (2,2) would have 4 PEs performing I/O operations.
44 !! When doing a read, each IO PE will receive a portion of data from 3 of the non-IO PEs and then write the aggregate.
45 !! When doing a write, each IO PE will read the data and then send a data portion to 3 of the non-IO PEs.
46 !> @ingroup fms_netcdf_unstructured_domain_io_mod
48  type(domainug) :: domain !< Unstructured domain.
49  character(len=FMS_PATH_LEN) :: non_mangled_path !< Non-domain-mangled path.
51 
52 !> @addtogroup fms_netcdf_unstructured_domain_io_mod
53 !> @{
77 
78 
79 contains
80 
81 !> @brief Open a netcdf file that is associated with an unstructured domain.
82 !! @return Flag telling if the open completed successfully.
83 function open_unstructured_domain_file(fileobj, path, mode, domain, nc_format, &
84  is_restart, dont_add_res_to_filename) &
85  result(success)
86 
87  type(fmsnetcdfunstructureddomainfile_t), intent(inout) :: fileobj !< File object.
88  character(len=*), intent(in) :: path !< File path.
89  character(len=*), intent(in) :: mode !< File mode. Allowed values
90  !! are "read", "append", "write", or
91  !! "overwrite".
92  type(domainug), intent(in) :: domain !< Unstructured domain.
93  character(len=*), intent(in), optional :: nc_format !< Netcdf format that
94  !! new files are written
95  !! as. Allowed values
96  !! are: "64bit", "classic",
97  !! or "netcdf4". Defaults to
98  !! "64bit".
99  logical, intent(in), optional :: is_restart !< Flag telling if this file
100  !! is a restart file. Defaults
101  !! to false.
102  logical, intent(in), optional :: dont_add_res_to_filename !< Flag indicating not to add
103  !! ".res" to the filename
104  logical :: success
105 
106  type(domainug), pointer :: io_domain
107  integer :: pelist_size
108  integer, dimension(:), allocatable :: pelist
109  character(len=FMS_PATH_LEN) :: buf
110  character(len=FMS_PATH_LEN) :: buf2
111  integer :: tile_id
112 
113  !Get the input domain's I/O domain pelist.
114  io_domain => mpp_get_ug_io_domain(domain)
115  if (.not. associated(io_domain)) then
116  call error("The input domain associated with the file:"//trim(fileobj%path)//" does not have an io_domain.")
117  endif
118  pelist_size = mpp_get_ug_domain_npes(io_domain)
119  allocate(pelist(pelist_size))
120  call mpp_get_ug_domain_pelist(io_domain, pelist)
121 
122  !Add the domain tile id to the file name (if necessary).
123  call string_copy(buf, path)
124  if (mpp_get_ug_domain_ntiles(domain) .gt. 1) then
125  tile_id = mpp_get_ug_domain_tile_id(domain)
126  call domain_tile_filepath_mangle(buf, path, tile_id)
127  endif
128 
129  success = .false.
130  if (string_compare(mode, "read", .true.) .or. string_compare(mode, "append", .true.)) then
131  !Only for reading: attempt to open non-distributed files.
132  success = netcdf_file_open(fileobj, buf, mode, nc_format, pelist, is_restart, dont_add_res_to_filename)
133  endif
134  if (.not. success) then
135  !Add the domain tile id to the file name (if necessary).
136  if (mpp_get_io_domain_ug_layout(domain) .gt. 1) then
137  tile_id = mpp_get_ug_domain_tile_id(io_domain)
138  call string_copy(buf2, buf)
139  call io_domain_tile_filepath_mangle(buf, buf2, tile_id)
140  endif
141 
142  !Open distributed files.
143  success = netcdf_file_open(fileobj, buf, mode, nc_format, pelist, is_restart, dont_add_res_to_filename)
144  endif
145  deallocate(pelist)
146 
147  if (.not. success) then
148  !This branch should only be entered if the file attempting to be read
149  !does not exist.
150  return
151  endif
152 
153  !Store/initialize necessary properties.
154  fileobj%domain = domain
155  call string_copy(fileobj%non_mangled_path, path)
157 
158 
159 !> @brief Wrapper to distinguish interfaces.
161 
162  type(fmsnetcdfunstructureddomainfile_t), intent(inout) :: fileobj !< File object.
163 
164  call netcdf_file_close(fileobj)
165 end subroutine close_unstructured_domain_file
166 
167 
168 !> @brief Add an unstructured dimension.
169 subroutine register_unstructured_dimension(fileobj, dim_name)
170 
171  type(fmsnetcdfunstructureddomainfile_t), intent(inout) :: fileobj !< File object.
172  character(len=*), intent(in) :: dim_name !< Dimension name.
173 
174  type(domainug),pointer :: io_domain
175  integer, dimension(:), allocatable :: c
176  integer, dimension(:), allocatable :: e
177 
178  allocate(c(size(fileobj%pelist)))
179  allocate(e(size(fileobj%pelist)))
180  io_domain => mpp_get_ug_io_domain(fileobj%domain)
181  call mpp_get_ug_compute_domains(io_domain, begin=c, size=e)
182  if (c(1) .ne. 1) then
183  c(:) = c(:) - c(1) + 1
184  endif
185  call register_compressed_dimension(fileobj, dim_name, c, e)
186  deallocate(c)
187  deallocate(e)
188 end subroutine register_unstructured_dimension
189 
190 
191 !> @brief Wrapper to distinguish interfaces.
192 subroutine register_unstructured_domain_variable(fileobj, variable_name, &
193  variable_type, dimensions, chunksizes)
194 
195  type(fmsnetcdfunstructureddomainfile_t), intent(in) :: fileobj !< File object.
196  character(len=*), intent(in) :: variable_name !< Variable name.
197  character(len=*), intent(in) :: variable_type !< Variable type. Allowed
198  !! values are: "int", "int64",
199  !! "float", or "double".
200  character(len=*), dimension(:), intent(in), optional :: dimensions !< Dimension names.
201  integer, intent(in), optional :: chunksizes(:) !< netcdf chunksize to use for this variable (netcdf4 only)
202 
203  call netcdf_add_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
205 
206 
207 !> @brief Wrapper to distinguish interfaces.
208 subroutine unstructured_write_restart(fileobj, unlim_dim_level)
209 
210  type(fmsnetcdfunstructureddomainfile_t), intent(in) :: fileobj !< File object.
211  integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
212 
213  call netcdf_save_restart(fileobj, unlim_dim_level)
214 end subroutine unstructured_write_restart
215 
216 
217 include "register_unstructured_domain_restart_variable.inc"
218 include "unstructured_domain_read.inc"
219 include "unstructured_domain_write.inc"
220 
221 
222 end module fms_netcdf_unstructured_domain_io_mod
subroutine unstructured_domain_read_4d(fileobj, variable_name, buf, unlim_dim_level, corner, edge_lengths, broadcast)
Wrapper to distinguish interfaces.
subroutine unstructured_domain_write_2d(fileobj, variable_name, variable_data, unlim_dim_level, corner, edge_lengths)
Wrapper to distinguish interfaces.
subroutine register_unstructured_domain_restart_variable_4d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine unstructured_domain_read_3d(fileobj, variable_name, buf, unlim_dim_level, corner, edge_lengths, broadcast)
Wrapper to distinguish interfaces.
subroutine unstructured_domain_write_3d(fileobj, variable_name, variable_data, unlim_dim_level, corner, edge_lengths)
Wrapper to distinguish interfaces.
subroutine register_unstructured_domain_restart_variable_2d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine unstructured_domain_write_0d(fileobj, variable_name, variable_data, unlim_dim_level, corner)
Wrapper to distinguish interfaces.
subroutine unstructured_domain_read_0d(fileobj, variable_name, buf, unlim_dim_level, corner, broadcast)
Wrapper to distinguish interfaces.
subroutine unstructured_domain_write_4d(fileobj, variable_name, variable_data, unlim_dim_level, corner, edge_lengths)
Wrapper to distinguish interfaces.
subroutine register_unstructured_domain_restart_variable_3d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine unstructured_domain_read_5d(fileobj, variable_name, buf, unlim_dim_level, corner, edge_lengths, broadcast)
Wrapper to distinguish interfaces.
subroutine unstructured_domain_read_2d(fileobj, variable_name, buf, unlim_dim_level, corner, edge_lengths, broadcast)
Wrapper to distinguish interfaces.
subroutine register_unstructured_domain_restart_variable_1d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine register_unstructured_domain_restart_variable_5d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine unstructured_domain_write_1d(fileobj, variable_name, variable_data, unlim_dim_level, corner, edge_lengths)
Wrapper to distinguish interfaces.
subroutine unstructured_domain_write_5d(fileobj, variable_name, variable_data, unlim_dim_level, corner, edge_lengths)
Wrapper to distinguish interfaces.
subroutine register_unstructured_domain_restart_variable_0d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine unstructured_domain_read_1d(fileobj, variable_name, buf, unlim_dim_level, corner, edge_lengths, broadcast)
Wrapper to distinguish interfaces.
subroutine, public error(mesg)
Print a message to stderr, then stop the program.
subroutine, public io_domain_tile_filepath_mangle(dest, source, io_domain_tile_id)
Add the I/O domain tile id to an input filepath.
logical function, public string_compare(string1, string2, ignore_case)
Compare strings.
subroutine, public domain_tile_filepath_mangle(dest, source, domain_tile_id)
Add the domain tile id to an input filepath.
subroutine, public register_unstructured_dimension(fileobj, dim_name)
Add an unstructured dimension.
logical function, public open_unstructured_domain_file(fileobj, path, mode, domain, nc_format, is_restart, dont_add_res_to_filename)
Open a netcdf file that is associated with an unstructured domain.
subroutine, public close_unstructured_domain_file(fileobj)
Wrapper to distinguish interfaces.
subroutine, public register_unstructured_domain_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
Wrapper to distinguish interfaces.
subroutine, public unstructured_write_restart(fileobj, unlim_dim_level)
Wrapper to distinguish interfaces.
Type to represent a netCDF file when on a domain decomposed unstructured grid. Used to do distributed...
Domain information for managing data on unstructured grids.
subroutine, public netcdf_file_close(fileobj)
Close a netcdf file.
Definition: netcdf_io.F90:768
subroutine, public register_compressed_dimension(fileobj, dimension_name, npes_corner, npes_nelems)
Add a compressed dimension.
Definition: netcdf_io.F90:954
subroutine, public netcdf_save_restart(fileobj, unlim_dim_level)
Loop through registered restart variables and write them to a netcdf file.
Definition: netcdf_io.F90:1129
subroutine, public netcdf_add_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
Add a variable to a file.
Definition: netcdf_io.F90:982
logical function, public netcdf_file_open(fileobj, path, mode, nc_format, pelist, is_restart, dont_add_res_to_filename, tile_comm, use_collective)
Open a netcdf file.
Definition: netcdf_io.F90:565
Type to represent a netCDF file. Can be used with multiple cores but only the root pe will perform an...
Definition: netcdf_io.F90:147