30 use fms_netcdf_domain_io_mod
31 use fms_netcdf_unstructured_domain_io_mod
33 use,
intrinsic :: iso_fortran_env, only: error_unit
38 integer,
private :: fms2_ncchksz = -1
54 integer,
intent(in) :: chksz
63 character(len=*),
intent(in) :: path
64 character(len=*),
intent(out) :: new_path
65 character(len=*),
intent(in),
optional :: directory
66 character(len=*),
intent(in),
optional :: timestamp
67 character(len=*),
intent(in),
optional :: new_name
69 character(len=FMS_PATH_LEN) :: dir
70 character(len=FMS_FILE_LEN) :: tstamp
71 character(len=FMS_PATH_LEN) :: nname
74 if (
present(directory))
then
75 call string_copy(dir, trim(directory)//
"/")
78 if (
present(timestamp))
then
79 call string_copy(tstamp, trim(timestamp)//
".")
81 call string_copy(nname, trim(path))
82 if (
present(new_name))
then
83 call string_copy(nname, trim(new_name))
85 call string_copy(new_path, trim(dir)//trim(tstamp)//trim(nname))
93 character(len=*),
intent(out) :: filename
99 call random_number(numr)
100 numi = transfer(numr, numi)
101 numi = iand(numi, z
'FFFFFF')
102 write(filename,
'(a,z6.6)')
"tmp", numi
118 integer,
dimension(:),
intent(in),
optional :: pelist
123 character(len=*),
intent(in),
optional :: path
129 if (
present(path))
then
130 call string_copy(fileobj%path, path)
134 fileobj%nc_format =
"classic"
135 fileobj%is_readonly = .false.
136 if (
present(pelist))
then
137 allocate(fileobj%pelist(
size(pelist)))
138 fileobj%pelist(:) = pelist(:)
140 allocate(fileobj%pelist(1))
141 fileobj%pelist(1) =
mpp_pe()
143 fileobj%io_root = fileobj%pelist(1)
144 fileobj%is_root =
mpp_pe() .eq. fileobj%io_root
145 fileobj%is_restart = .true.
146 fileobj%is_diskless = .true.
147 cmode = ior(nf90_noclobber, nf90_classic_model)
148 cmode = ior(cmode, nf90_diskless)
149 if (fms2_ncchksz == -1)
call error(
"create_diskless_netcdf_file :: fms2_ncchksz not set. Call fms2_io init first")
150 err = nf90_create(trim(fileobj%path), cmode, fileobj%ncid, chunksize=fms2_ncchksz)
151 success = err .eq. nf90_noerr
152 if (.not. success)
then
153 deallocate(fileobj%pelist)
156 allocate(fileobj%restart_vars(max_num_restart_vars))
157 fileobj%num_restart_vars = 0
158 allocate(fileobj%compressed_dims(max_num_compressed_dims))
159 fileobj%num_compressed_dims = 0
175 character(len=nf90_max_name) :: n
176 character(len=nf90_max_name) :: varname
177 character(len=nf90_max_name),
dimension(nf90_max_dims) :: dimnames
178 integer,
dimension(nf90_max_dims) :: dimlens
180 integer,
dimension(nf90_max_var_dims) :: dimids
181 integer,
dimension(nf90_max_var_dims) :: d
182 integer :: ulim_dimid
187 integer(kind=i4_kind),
dimension(:),
allocatable :: buf_int
188 real(kind=r4_kind),
dimension(:),
allocatable :: buf_float
189 real(kind=r8_kind),
dimension(:),
allocatable :: buf_double
190 character(len=200) :: append_error_msg
192 append_error_msg =
"copy_metadata: original file:"//trim(fileobj%path)//
" new file:"//trim(new_fileobj%path)
193 if (fileobj%is_root .and. .not. new_fileobj%is_readonly)
then
197 err = nf90_inquire(fileobj%ncid, nattributes=natt)
200 err = nf90_inq_attname(fileobj%ncid, nf90_global, i, n)
202 err = nf90_copy_att(fileobj%ncid, nf90_global, n, new_fileobj%ncid, nf90_global)
207 err = nf90_inquire(fileobj%ncid, ndimensions=ndim)
209 err = nf90_inquire(fileobj%ncid, unlimiteddimid=ulim_dimid)
212 err = nf90_inquire_dimension(fileobj%ncid, i, dimnames(i), dimlens(i))
214 if (i .eq. ulim_dimid)
then
215 err = nf90_def_dim(new_fileobj%ncid, dimnames(i), nf90_unlimited, dimids(i))
216 ulim_dimid = dimids(i)
218 err = nf90_def_dim(new_fileobj%ncid, dimnames(i), dimlens(i), dimids(i))
224 err = nf90_inquire(fileobj%ncid, nvariables=nvar)
227 err = nf90_inquire_variable(fileobj%ncid, i, varname, xtype, varndim, d, natt)
232 err = nf90_inquire_dimension(fileobj%ncid, d(j), n)
243 err = nf90_def_var(new_fileobj%ncid, varname, xtype, d(1:varndim), varid)
247 if (varndim .eq. 1 .and. d(1) .ne. ulim_dimid)
then
252 if (xtype .eq. nf90_int)
then
253 allocate(buf_int(dimlens(k)))
254 err = nf90_get_var(fileobj%ncid, i, buf_int)
256 err = nf90_put_var(new_fileobj%ncid, varid, buf_int)
258 elseif (xtype .eq. nf90_float)
then
259 allocate(buf_float(dimlens(k)))
260 err = nf90_get_var(fileobj%ncid, i, buf_float)
262 err = nf90_put_var(new_fileobj%ncid, varid, buf_float)
263 deallocate(buf_float)
264 elseif (xtype .eq. nf90_double)
then
265 allocate(buf_double(dimlens(k)))
266 err = nf90_get_var(fileobj%ncid, i, buf_double)
268 err = nf90_put_var(new_fileobj%ncid, varid, buf_double)
269 deallocate(buf_double)
271 call error(append_error_msg//
" "//trim(varname)//
" has an unsupported type, "&
272 //
"only nf90_int, nf90_float, and nf90_double are currently supported")
285 err = nf90_inq_attname(fileobj%ncid, i, j, n)
287 err = nf90_copy_att(fileobj%ncid, i, n, new_fileobj%ncid, varid)
293 if (new_fileobj%is_restart)
then
295 do i = 1, fileobj%num_restart_vars
296 new_fileobj%restart_vars(i)%varname = fileobj%restart_vars(i)%varname
297 if (
associated(fileobj%restart_vars(i)%data0d))
then
298 new_fileobj%restart_vars(i)%data0d => fileobj%restart_vars(i)%data0d
299 elseif (
associated(fileobj%restart_vars(i)%data1d))
then
300 new_fileobj%restart_vars(i)%data1d => fileobj%restart_vars(i)%data1d
301 elseif (
associated(fileobj%restart_vars(i)%data2d))
then
302 new_fileobj%restart_vars(i)%data2d => fileobj%restart_vars(i)%data2d
303 elseif (
associated(fileobj%restart_vars(i)%data3d))
then
304 new_fileobj%restart_vars(i)%data3d => fileobj%restart_vars(i)%data3d
305 elseif (
associated(fileobj%restart_vars(i)%data4d))
then
306 new_fileobj%restart_vars(i)%data4d => fileobj%restart_vars(i)%data4d
308 call error(
"this branch should not be reached.")
311 new_fileobj%num_restart_vars = fileobj%num_restart_vars
315 do i = 1, fileobj%num_compressed_dims
316 new_fileobj%compressed_dims(i)%dimname = fileobj%compressed_dims(i)%dimname
317 k =
size(fileobj%compressed_dims(i)%npes_corner)
318 allocate(new_fileobj%compressed_dims(i)%npes_corner(k))
319 allocate(new_fileobj%compressed_dims(i)%npes_nelems(k))
321 new_fileobj%compressed_dims(i)%npes_corner(j) = fileobj%compressed_dims(i)%npes_corner(j)
322 new_fileobj%compressed_dims(i)%npes_nelems(j) = fileobj%compressed_dims(i)%npes_nelems(j)
324 new_fileobj%compressed_dims(i)%nelems = fileobj%compressed_dims(i)%nelems
326 new_fileobj%num_compressed_dims = fileobj%num_compressed_dims
335 character(len=*),
intent(in) :: path
336 character(len=*),
intent(in) :: mode
340 character(len=*),
intent(in),
optional :: nc_format
351 fileobj%pelist, fileobj%is_restart)
352 if (.not. success)
then
353 call error(
"error opening file "//trim(path)//
".")
366 integer,
dimension(:),
intent(in),
optional :: pelist
371 character(len=*),
intent(in),
optional :: path
383 integer,
intent(in),
optional :: unlim_dim_level
385 character(len=*),
intent(in),
optional :: directory
386 character(len=*),
intent(in),
optional :: timestamp
387 character(len=*),
intent(in),
optional :: filename
388 character(len=*),
intent(in),
optional :: nc_format
395 character(len=FMS_PATH_LEN) :: new_name
398 logical :: close_new_file
400 call get_new_filename(fileobj%path, new_name, directory, timestamp, filename)
403 close_new_file = .false.
405 call new_netcdf_file(fileobj, new_name,
"write", new_fileobj, nc_format)
407 close_new_file = .true.
410 if (close_new_file)
then
422 integer,
intent(in),
optional :: unlim_dim_level
424 character(len=*),
intent(in),
optional :: directory
425 character(len=*),
intent(in),
optional :: timestamp
426 character(len=*),
intent(in),
optional :: filename
428 character(len=FMS_PATH_LEN) :: new_name
431 logical :: close_new_file
433 call get_new_filename(fileobj%path, new_name, directory, timestamp, filename)
436 close_new_file = .false.
440 close_new_file = .true.
443 if (close_new_file)
then
456 type(
domain2d),
intent(in) :: domain
457 character(len=*),
intent(in),
optional :: path
460 type(
domain2d),
pointer :: io_domain
461 integer :: pelist_size
462 integer,
dimension(:),
allocatable :: pelist
465 if (.not.
associated(io_domain))
then
466 call error(
"The domain associated with the file: "//trim(fileobj%path)//
" does not have an io_domain.")
469 allocate(pelist(pelist_size))
473 fileobj%domain = domain
474 allocate(fileobj%xdims(max_num_domain_decomposed_dims))
476 allocate(fileobj%ydims(max_num_domain_decomposed_dims))
478 call string_copy(fileobj%non_mangled_path, fileobj%path)
487 character(len=*),
intent(in) :: path
488 character(len=*),
intent(in) :: mode
491 character(len=*),
intent(in),
optional :: nc_format
501 success =
open_domain_file(new_fileobj, path, mode, fileobj%domain, nc_format, &
503 if (.not. success)
then
504 call error(
"error opening file "//trim(path)//
".")
508 call string_copy(new_fileobj%xdims(i)%varname, fileobj%xdims(i)%varname)
509 new_fileobj%xdims(i)%pos = fileobj%xdims(i)%pos
511 new_fileobj%nx = fileobj%nx
513 call string_copy(new_fileobj%ydims(i)%varname, fileobj%ydims(i)%varname)
514 new_fileobj%ydims(i)%pos = fileobj%ydims(i)%pos
516 new_fileobj%ny = fileobj%ny
526 integer,
intent(in),
optional :: unlim_dim_level
527 character(len=*),
intent(in),
optional :: directory
528 character(len=*),
intent(in),
optional :: timestamp
529 character(len=*),
intent(in),
optional :: filename
530 character(len=*),
intent(in),
optional :: nc_format
537 character(len=FMS_PATH_LEN) :: new_name
540 logical :: close_new_file
542 call get_new_filename(fileobj%non_mangled_path, new_name, directory, timestamp, filename)
545 close_new_file = .false.
547 call new_domain_file(fileobj, new_name,
"write", new_fileobj, nc_format)
549 close_new_file = .true.
552 if (close_new_file)
then
561 filename, ignore_checksum)
564 integer,
intent(in),
optional :: unlim_dim_level
565 character(len=*),
intent(in),
optional :: directory
566 character(len=*),
intent(in),
optional :: timestamp
567 character(len=*),
intent(in),
optional :: filename
568 logical,
intent(in),
optional :: ignore_checksum
570 character(len=FMS_PATH_LEN) :: new_name
573 logical :: close_new_file
575 call get_new_filename(fileobj%non_mangled_path, new_name, directory, timestamp, filename)
578 close_new_file = .false.
582 close_new_file = .true.
585 if (close_new_file)
then
598 type(
domainug),
intent(in) :: domain
599 character(len=*),
intent(in),
optional :: path
602 type(
domainug),
pointer :: io_domain
603 integer :: pelist_size
604 integer,
dimension(:),
allocatable :: pelist
606 io_domain => mpp_get_ug_io_domain(domain)
607 if (.not.
associated(io_domain))
then
608 call error(
"The domain associated with the file: "//trim(fileobj%path)//
" does have an io_domain.")
610 pelist_size = mpp_get_ug_domain_npes(io_domain)
611 allocate(pelist(pelist_size))
612 call mpp_get_ug_domain_pelist(io_domain, pelist)
615 fileobj%domain = domain
616 call string_copy(fileobj%non_mangled_path, fileobj%path)
625 character(len=*),
intent(in) :: path
626 character(len=*),
intent(in) :: mode
629 character(len=*),
intent(in),
optional :: nc_format
639 nc_format, fileobj%is_restart)
640 if (.not. success)
then
641 call error(
"error while opening file "//trim(path)//
".")
652 integer,
intent(in),
optional :: unlim_dim_level
653 character(len=*),
intent(in),
optional :: directory
654 character(len=*),
intent(in),
optional :: timestamp
655 character(len=*),
intent(in),
optional :: filename
656 character(len=*),
intent(in),
optional :: nc_format
663 character(len=256) :: new_name
666 call get_new_filename(fileobj%non_mangled_path, new_name, directory, timestamp, filename)
677 end module blackboxio
logical function, public create_diskless_netcdf_file_wrap(fileobj, pelist, path)
Wrapper to distinguish interfaces.
subroutine new_netcdf_file(fileobj, path, mode, new_fileobj, nc_format)
Make a copy of a file's metadata to support "intermediate restarts".
logical function, public create_diskless_unstructured_domain_file(fileobj, domain, path)
Create a "diskless" netcdf file to act as a buffer to support our "register data to a file wi...
subroutine, public unstructured_write_restart_wrap(fileobj, unlim_dim_level, directory, timestamp, filename, nc_format)
Wrapper to distinguish interfaces.
subroutine, public save_domain_restart_wrap(fileobj, unlim_dim_level, directory, timestamp, filename, nc_format)
Loop through registered restart variables and write them to a netcdf file.
subroutine tempfile(filename)
Create a unique filename (poor man's version of mktemp).
logical function, public create_diskless_domain_file(fileobj, domain, path)
Create a "diskless" netcdf file to act as a buffer to support our "register data to a file wi...
subroutine new_unstructured_domain_file(fileobj, path, mode, new_fileobj, nc_format)
Make a copy of a file's metadata to support "intermediate restarts".
subroutine get_new_filename(path, new_path, directory, timestamp, new_name)
Create a new file path.
subroutine new_domain_file(fileobj, path, mode, new_fileobj, nc_format)
Make a copy of a file's metadata to support "intermediate restarts".
subroutine, public restore_domain_state_wrap(fileobj, unlim_dim_level, directory, timestamp, filename, ignore_checksum)
Loop through registered restart variables and read them from a netcdf file.
subroutine, public netcdf_restore_state_wrap(fileobj, unlim_dim_level, directory, timestamp, filename)
Loop through registered restart variables and read them from a netcdf file.
subroutine copy_metadata(fileobj, new_fileobj)
Copy metadata from one file object to another.
subroutine, public blackboxio_init(chksz)
Accepts the namelist fms2_io_nml variables relevant to blackboxio.
subroutine, public netcdf_save_restart_wrap2(fileobj, unlim_dim_level, directory, timestamp, filename, nc_format)
Support for writing new restarts from a diskless file.
logical function create_diskless_netcdf_file(fileobj, pelist, path)
Create a "diskless" netcdf file to act as a buffer to support our "register data to a file wi...
logical function, public file_exists(path)
Determine if a file exists.
subroutine, public error(mesg)
Print a message to stderr, then stop the program.
logical function, public string_compare(string1, string2, ignore_case)
Compare strings.
subroutine, public save_domain_restart(fileobj, unlim_dim_level)
Loop through registered restart variables and write them to a netcdf file.
logical function, public open_domain_file(fileobj, path, mode, domain, nc_format, is_restart, dont_add_res_to_filename)
Open a domain netcdf file.
subroutine, public close_domain_file(fileobj)
Close a domain netcdf file.
subroutine, public restore_domain_state(fileobj, unlim_dim_level, ignore_checksum)
Loop through registered restart variables and read them from a netcdf file.
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.
netcdf unstructured domain file type.
integer function mpp_get_domain_npes(domain)
Set user stack size.
type(domain2d) function, pointer mpp_get_io_domain(domain)
Set user stack size.
Retrieve list of PEs associated with a domain decomposition. The 1D version of this call returns an a...
The domain2D type contains all the necessary information to define the global, compute and data domai...
Domain information for managing data on unstructured grids.
integer function mpp_pe()
Returns processor ID.
subroutine, public netcdf_restore_state(fileobj, unlim_dim_level)
Loop through registered restart variables and read them from a netcdf file.
subroutine, public netcdf_file_close(fileobj)
Close a netcdf file.
logical function, public netcdf_file_open(fileobj, path, mode, nc_format, pelist, is_restart, dont_add_res_to_filename)
Open a netcdf file.
subroutine, public set_netcdf_mode(ncid, mode)
Switch to the correct netcdf mode.
subroutine, public check_netcdf_code(err, msg)
Check for errors returned by netcdf.
subroutine, public netcdf_save_restart(fileobj, unlim_dim_level)
Loop through registered restart variables and write them to a netcdf file.