FV3 Bundle
fms_io.F90
Go to the documentation of this file.
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 module fms_io_mod
21 #include <fms_platform.h>
22 
23 !
24 !
25 ! <CONTACT EMAIL="Zhi.Liang@noaa.gov">
26 ! Zhi Liang
27 ! </CONTACT>
28 
29 ! <CONTACT EMAIL="Matthew.Harrison@noaa.gov">
30 ! M.J. Harrison
31 ! </CONTACT>
32 !
33 ! <REVIEWER EMAIL="Matthew.Harrison@noaa.gov">
34 ! M.J. Harrison
35 ! </REVIEWER>
36 
37 ! <REVIEWER EMAIL="Bruce.Wyman@noaa.gov">
38 ! B. Wyman
39 ! </REVIEWER>
40 
41 !<DESCRIPTION>
42 ! This module is for writing and reading restart data in NetCDF format.
43 ! fms_io_init must be called before the first write_data/read_data call
44 ! For writing, fms_io_exit must be called after ALL write calls have
45 ! been made. Typically, fms_io_init and fms_io_exit are placed in the
46 ! main (driver) program while read_data and write_data can be called where needed.
47 ! Presently, two combinations of threading and fileset are supported, users can choose
48 ! one line of the following by setting namelist:
49 !
50 ! With the introduction of netCDF restart files, there is a need for a global
51 ! switch to turn on/off netCDF restart options in all of the modules that deal with
52 ! restart files. Here two more namelist variables (logical type) are introduced to fms_io
53 !
54 ! fms_netcdf_override
55 ! fms_netcdf_restart
56 !
57 ! because default values of both flags are .true., the default behavior of the entire model is
58 ! to use netCDF IO mode. To turn off netCDF restart, simply set fms_netcdf_restart to .false.
59 !
60 !</DESCRIPTION>
61 ! <NAMELIST NAME="fms_io_nml">
62 ! <DATA NAME="threading_read" TYPE="character">
63 ! threading_read can be 'single' or 'multi'
64 ! </DATA>
65 ! <DATA NAME="fms_netcdf_override" TYPE="logical">
66 ! .true. : fms_netcdf_restart overrides individual do_netcdf_restart value (default behavior)
67 ! .false.: individual module settings has a precedence over the global setting, therefore fms_netcdf_restart is ignored
68 ! </DATA>
69 ! <DATA NAME="fms_netcdf_restart" TYPE="logical">
70 ! .true. : all modules deal with restart files will operate under netCDF mode (default behavior)
71 ! .false.: all modules deal with restart files will operate under binary mode
72 ! This flag is effective only when fms_netcdf_override is .true. When fms_netcdf_override is .false., individual
73 ! module setting takes over.
74 ! </DATA>
75 ! <DATA NAME="time_stamped_restart" TYPE="logical">
76 ! .true. : time_stamp will be added to the restart file name as a prefix when
77 ! optional argument time_stamp is passed into routine save_restart.
78 ! .false.: time_stmp will not be added to the restart file name even though
79 ! time_stamp is passed into save_restart.
80 ! default is true.
81 ! </DATA>
82 ! <DATA NAME="print_chksum" TYPE="logical">
83 ! set print_chksum (default is false) to true to print out chksum of fields that are
84 ! read and written through save_restart/restore_state. The chksum is accross all the
85 ! processors, so there will be only one chksum even there are multiple-tiles in the
86 ! grid. For the multiple case, the filename appeared in the message will contain
87 ! tile1 because the message is print out from root pe and on root pe the tile id is tile1.
88 ! </DATA>
89 ! <DATA NAME="debug_mask_list" TYPE="logical">
90 ! set debug_mask_list (default is false) to true to print out mask_list reading from mask_table.
91 ! </DATA>
92 ! <DATA NAME="checksum_required" TYPE="logical">
93 ! Set checksum_required (default is true) to true to compare checksums stored in the attribute of a
94 ! field against the checksum after reading in the data. This check mitigates the possibility of data
95 ! that gets corrupted on write or read from being used in a n ongoing fashion. The checksum is across
96 ! all the processors, so there will be only one checksum even if there are multiple-tiles in the
97 ! grid. For the decomposed file case, the filename appearing in the message will contain tile1
98 ! because the message is printed out from the root pe and on root pe the tile id is tile1.
99 !
100 ! Set checksum_required to false if you do not want to compare checksums.
101 ! </DATA>
102 
103 !</NAMELIST>
104 
105 use mpp_io_mod, only: mpp_open, mpp_close, mpp_io_init, mpp_io_exit, mpp_read, mpp_write
106 use mpp_io_mod, only: mpp_write_meta, mpp_get_info, mpp_get_atts, mpp_get_fields
109 use mpp_io_mod, only: mpp_get_axes, mpp_get_axis_data, mpp_get_att_char, mpp_get_att_name
110 use mpp_io_mod, only: mpp_get_att_real_scalar, mpp_attribute_exist, mpp_is_dist_ioroot
112 use mpp_io_mod, only: mpp_netcdf, mpp_ascii, mpp_multi, mpp_single, mpp_overwr, mpp_rdonly
113 use mpp_io_mod, only: mpp_ieee32, mpp_native, mpp_delete, mpp_append, mpp_sequential, mpp_direct
114 use mpp_io_mod, only: max_file_size, mpp_get_att_value
115 use mpp_io_mod, only: mpp_get_dimension_length
116 use mpp_domains_mod, only: domain2d, domain1d, null_domain1d, null_domain2d, operator( .EQ. )
117 use mpp_domains_mod, only: center, east, west, north, south, corner
118 use mpp_domains_mod, only: mpp_get_domain_components, mpp_get_compute_domain, mpp_get_data_domain
119 use mpp_domains_mod, only: mpp_get_domain_shift, mpp_get_global_domain, mpp_global_field, mpp_domain_is_tile_root_pe
120 use mpp_domains_mod, only: mpp_get_ntile_count, mpp_get_current_ntile, mpp_get_tile_id
121 use mpp_domains_mod, only: mpp_get_pelist, mpp_get_io_domain, mpp_get_domain_npes
122 use mpp_domains_mod, only: domainug, mpp_pass_sg_to_ug, mpp_get_ug_domain_ntiles, mpp_get_ug_domain_tile_id
123 use mpp_mod, only: mpp_error, fatal, note, warning, mpp_pe, mpp_root_pe, mpp_npes, stdlog, stdout
124 use mpp_mod, only: mpp_broadcast, all_pes, mpp_chksum, mpp_get_current_pelist, mpp_npes, lowercase
125 use mpp_mod, only: input_nml_file, mpp_get_current_pelist_name, uppercase
126 use mpp_mod, only: mpp_gather, mpp_scatter, mpp_send, mpp_recv, mpp_sync_self, comm_tag_1, event_recv
127 use mpp_mod, only: mpp_fill_double,mpp_fill_int
128 
129 use platform_mod, only: r8_kind
130 
131 !----------
132 !ug support
133 use mpp_parameter_mod, only: comm_tag_2
134 use mpp_domains_mod, only: mpp_get_ug_io_domain
135 use mpp_domains_mod, only: mpp_domain_ug_is_tile_root_pe
136 use mpp_domains_mod, only: mpp_get_ug_domain_npes
137 use mpp_domains_mod, only: mpp_get_ug_domain_pelist
140 use mpp_io_mod, only: mpp_file_is_opened
141 !----------
142 
143 implicit none
144 private
145 
146 
147 integer, parameter, private :: max_split_file = 50
148 integer, parameter, private :: max_fields=400
149 integer, parameter, private :: max_axes=40
150 integer, parameter, private :: max_atts=20
151 integer, parameter, private :: max_domains = 10
152 integer, parameter, private :: max_time_level_register = 2
153 integer, parameter, private :: max_time_level_write = 20
154 integer, parameter :: max_axis_size=10000
155 
156 ! Index postions for axes in restart_file_type
157 ! This is done so the user may define the axes
158 ! in any order but a check can be performed
159 ! to ensure no registration of duplicate axis
160 
161 !----------
162 !ug support
163 integer(INT_KIND),parameter,public :: xidx = 1
164 integer(INT_KIND),parameter,public :: yidx = 2
165 integer(INT_KIND),parameter,public :: cidx = 3
166 integer(INT_KIND),parameter,public :: zidx = 4
167 integer(INT_KIND),parameter,public :: hidx = 5
168 integer(INT_KIND),parameter,public :: tidx = 6
169 integer(INT_KIND),parameter,public :: uidx = 7
170 integer(INT_KIND),parameter,public :: ccidx = 8
171 !---------
172 
173 integer, parameter, private :: nidx=8
174 
176  type(meta_type), pointer :: prev=>null(), next=>null()
177 !!$ Gfortran on gaea does not yet support deferred length character strings
178 !!$ character(len=:),allocatable :: name
179  character(len=256) :: name
180  real, allocatable :: rval(:)
181  integer, allocatable :: ival(:)
182 !!$ Gfortran on gaea does not yet support deferred length character strings
183 !!$ character(len=:), allocatable :: cval
184  character(len=256) :: cval
185 end type meta_type
186 
188  private
189  character(len=128) :: name = ''
190  character(len=128) :: units = ''
191  character(len=128) :: longname = ''
192  character(len=8) :: cartesian = ''
193  character(len=256) :: compressed = ''
194  character(len=128) :: dimlen_name = ''
195  character(len=128) :: dimlen_lname = ''
196  character(len=128) :: calendar = ''
197  integer :: sense !Orientation of z axis definition
198  integer :: dimlen !max dim of elements across global domain
199  real :: min !valid min for real axis data
200  integer :: imin !valid min for integer axis data
201  integer,allocatable :: idx(:) !compressed io-domain index vector
202  integer,allocatable :: nelems(:) !num elements for each rank in io domain
203  real, pointer :: data(:) =>null() !real axis values (not used if time axis)
204  type(domain2d),pointer :: domain =>null() ! domain associated with compressed axis
205 
206 !----------
207 !ug support
208  type(domainug),pointer :: domain_ug => null() !<A pointer to an unstructured mpp domain.
209  integer(INT_KIND) :: nelems_for_current_rank !<The number of grid points registered to the current rank (used for error checking).
210 !----------
211 
212 end type ax_type
213 
215  private
216  character(len=128) :: name = ''
217  character(len=128) :: longname = ''
218  character(len=128) :: units = ''
219  real, dimension(:,:,:,:), _allocatable :: buffer _null
220  logical :: domain_present = .false.
221  integer :: domain_idx = -1
222  logical :: is_dimvar = .false.
223  logical :: read_only = .false.
224  logical :: owns_data = .false. ! if true, restart owns the data and will deallocate them when freed
225  type(fieldtype) :: field
226  type(axistype) :: axis
227  integer :: position
228  integer :: ndim
229  integer :: siz(5) ! X/Y/Z/T/A extent of fields (data domain
230  ! size for distributed writes;global size for reads)
231  integer :: gsiz(4) ! global X/Y/Z/A extent of fields
232  integer :: id_axes(4) ! store index for x/y/z/a axistype.
233  logical :: initialized ! indicate if the field is read or not in routine save_state.
234  logical :: mandatory ! indicate if the field is mandatory to be when restart.
235  integer :: is, ie, js, je ! index of the data in compute domain
236  real :: default_data
237  character(len=8) :: compressed_axis !< If on a compressed axis, which axis
238  integer, dimension(:), allocatable :: pelist
239  integer :: ishift, jshift ! can be used to shift indices when no_domain=T
240  integer :: x_halo, y_halo ! can be used to indicate halo size when no_domain=T
241 
242 !----------
243 !ug support
244  type(domainug),pointer :: domain_ug => null() !<A pointer to an unstructured mpp domain.
245  integer(INT_KIND),dimension(5) :: field_dimension_order !<Array telling the ordering of the dimensions for the field.
246  integer(INT_KIND),dimension(NIDX) :: field_dimension_sizes !<Array of sizes of the dimensions for the field.
247 !----------
248 
249 end type var_type
250 
251 type ptr0dr
252  real, pointer :: p => null()
253 end type ptr0dr
254 
255 type ptr1dr
256  real, dimension(:), pointer :: p => null()
257 end type ptr1dr
258 
259 type ptr2dr
260  real, dimension(:,:), pointer :: p => null()
261 end type ptr2dr
262 
263 type ptr3dr
264  real, dimension(:,:,:), pointer :: p => null()
265 end type ptr3dr
266 
268  real(DOUBLE_KIND), dimension(:,:), pointer :: p => null()
269 end type ptr2dr8
270 
272  real(DOUBLE_KIND), dimension(:,:,:), pointer :: p => null()
273 end type ptr3dr8
274 
275 type ptr4dr
276  real, dimension(:,:,:,:), pointer :: p => null()
277 end type ptr4dr
278 
279 type ptr0di
280  integer, pointer :: p => null()
281 end type ptr0di
282 
283 type ptr1di
284  integer, dimension(:), pointer :: p => null()
285 end type ptr1di
286 
287 type ptr2di
288  integer, dimension(:,:), pointer :: p => null()
289 end type ptr2di
290 
291 type ptr3di
292  integer, dimension(:,:,:), pointer :: p => null()
293 end type ptr3di
294 
296  private
297  integer :: unit = -1 ! mpp_io unit for netcdf file
298  character(len=128) :: name = ''
299  integer :: register_id = 0
300  integer :: nvar = 0
301  integer :: natt = 0
302  integer :: max_ntime = 0
303  logical :: is_root_pe = .false.
304  logical :: is_compressed = .false.
305  logical :: unlimited_axis = .false.
306  integer :: tile_count = 1
307  type(ax_type), allocatable :: axes(:) ! Currently define X,Y,Compressed, unlimited and maybe Z
308  type(meta_type), pointer :: first =>null() ! pointer to first additional global metadata element
309  type(var_type), dimension(:), pointer :: var => null()
310  type(ptr0dr), dimension(:,:), pointer :: p0dr => null()
311  type(ptr1dr), dimension(:,:), pointer :: p1dr => null()
312  type(ptr2dr), dimension(:,:), pointer :: p2dr => null()
313  type(ptr3dr), dimension(:,:), pointer :: p3dr => null()
314  type(ptr2dr8), dimension(:,:), pointer :: p2dr8 => null()
315  type(ptr3dr8), dimension(:,:), pointer :: p3dr8 => null()
316  type(ptr4dr), dimension(:,:), pointer :: p4dr => null()
317  type(ptr0di), dimension(:,:), pointer :: p0di => null()
318  type(ptr1di), dimension(:,:), pointer :: p1di => null()
319  type(ptr2di), dimension(:,:), pointer :: p2di => null()
320  type(ptr3di), dimension(:,:), pointer :: p3di => null()
321 end type restart_file_type
322 
323 interface read_data
324  module procedure read_data_4d_new
325  module procedure read_data_3d_new
326  module procedure read_data_2d_new
327  module procedure read_data_2d_ug
328  module procedure read_data_1d_new
329  module procedure read_data_scalar_new
330  module procedure read_data_i3d_new
331  module procedure read_data_i2d_new
332  module procedure read_data_i1d_new
333  module procedure read_data_iscalar_new
334  module procedure read_data_2d, read_ldata_2d, read_idata_2d
335  module procedure read_data_3d, read_data_4d
336 #ifdef OVERLOAD_C8
337  module procedure read_cdata_2d,read_cdata_3d,read_cdata_4d
338 #endif
339  module procedure read_data_text
340  module procedure read_data_2d_region
341  module procedure read_data_3d_region
342 #ifdef OVERLOAD_R8
343  module procedure read_data_2d_region_r8
344  module procedure read_data_3d_region_r8
345 #endif
346 end interface
347 
349  module procedure read_distributed_r1d
350  module procedure read_distributed_r3d
351  module procedure read_distributed_r5d
352  module procedure read_distributed_i1d
353  module procedure read_distributed_iscalar
354  module procedure read_distributed_a1d
355 end interface
356 
357 ! Only need read compressed att; write is handled in with
358 ! mpp_io calls in save_compressed_restart
360  module procedure read_compressed_i1d
361  module procedure read_compressed_i2d
362  module procedure read_compressed_1d
363  module procedure read_compressed_2d
364  module procedure read_compressed_3d
365 end interface read_compressed
366 
367 interface write_data
368  module procedure write_data_4d_new
369  module procedure write_data_3d_new
370  module procedure write_data_2d_new
371  module procedure write_data_1d_new
372  module procedure write_data_scalar_new
373  module procedure write_data_i3d_new
374  module procedure write_data_i2d_new
375  module procedure write_data_i1d_new
376  module procedure write_data_iscalar_new
377  module procedure write_data_2d, write_ldata_2d, write_idata_2d
378  module procedure write_data_3d, write_data_4d
379 #ifdef OVERLOAD_C8
380  module procedure write_cdata_2d,write_cdata_3d,write_cdata_4d
381 #endif
382 end interface
383 
385  module procedure register_restart_field_r0d
386  module procedure register_restart_field_r1d
387  module procedure register_restart_field_r2d
388  module procedure register_restart_field_r3d
389 #ifdef OVERLOAD_R8
390  module procedure register_restart_field_r2d8
391  module procedure register_restart_field_r3d8
392  module procedure register_restart_field_r2d8_2level
393  module procedure register_restart_field_r3d8_2level
394 #endif
395  module procedure register_restart_field_r4d
396  module procedure register_restart_field_i0d
397  module procedure register_restart_field_i1d
398  module procedure register_restart_field_i2d
399  module procedure register_restart_field_i3d
400  module procedure register_restart_field_r0d_2level
401  module procedure register_restart_field_r1d_2level
402  module procedure register_restart_field_r2d_2level
403  module procedure register_restart_field_r3d_2level
404  module procedure register_restart_field_i0d_2level
405  module procedure register_restart_field_i1d_2level
406  module procedure register_restart_field_i2d_2level
407  module procedure register_restart_field_i3d_2level
408  module procedure register_restart_region_r2d
409  module procedure register_restart_region_r3d
410 end interface
411 
413  module procedure register_restart_axis_r1d
414  module procedure register_restart_axis_i1d
415  module procedure register_restart_axis_unlimited
416 end interface
417 
419  module procedure reset_field_pointer_r0d
420  module procedure reset_field_pointer_r1d
421  module procedure reset_field_pointer_r2d
422  module procedure reset_field_pointer_r3d
423  module procedure reset_field_pointer_r4d
424  module procedure reset_field_pointer_i0d
425  module procedure reset_field_pointer_i1d
426  module procedure reset_field_pointer_i2d
427  module procedure reset_field_pointer_i3d
428  module procedure reset_field_pointer_r0d_2level
429  module procedure reset_field_pointer_r1d_2level
430  module procedure reset_field_pointer_r2d_2level
431  module procedure reset_field_pointer_r3d_2level
432  module procedure reset_field_pointer_i0d_2level
433  module procedure reset_field_pointer_i1d_2level
434  module procedure reset_field_pointer_i2d_2level
435  module procedure reset_field_pointer_i3d_2level
436 end interface
437 
438 interface restore_state
439  module procedure restore_state_all
440  module procedure restore_state_one_field
441 end interface
442 
444  module procedure query_initialized_id
445  module procedure query_initialized_name
446  module procedure query_initialized_r2d
447  module procedure query_initialized_r3d
448  module procedure query_initialized_r4d
449 end interface
450 
452  module procedure set_initialized_id
453  module procedure set_initialized_name
454  module procedure set_initialized_r2d
455  module procedure set_initialized_r3d
456  module procedure set_initialized_r4d
457 end interface
458 
460  module procedure get_global_att_value_text
461  module procedure get_global_att_value_real
462 end interface
463 
465  module procedure get_var_att_value_text
466 end interface
467 
469  module procedure parse_mask_table_2d
470  module procedure parse_mask_table_3d
471 end interface
472 
474  module procedure get_mosaic_tile_file_sg
475  module procedure get_mosaic_tile_file_ug
476 end interface
477 
478 
479 integer :: num_files_r = 0 ! number of currently opened files for reading
480 integer :: num_files_w = 0 ! number of currently opened files for writing
481 integer :: num_domains = 0 ! number of domains in array_domain
482 integer :: num_registered_files = 0 ! mumber of files registered by calling register_restart_file
483 
484 integer :: thread_r, form
485 logical :: module_is_initialized = .false.
486 
487 character(len=128):: error_msg
488 logical :: great_circle_algorithm=.false.
489 
490 !------ private data, pointer to current 2d domain ------
491 ! entrained from fms_mod. This will be deprecated in the future.
492 type(domain2d), pointer, private :: current_domain =>null()
493 
494 integer, private :: is,ie,js,je ! compute domain
495 integer, private :: isd,ied,jsd,jed ! data domain
496 integer, private :: isg,ieg,jsg,jeg ! global domain
497 character(len=128), dimension(:), allocatable :: registered_file ! file names registered through register_restart_file
498 type(restart_file_type), dimension(:), allocatable :: files_read ! store files that are read through read_data
499 type(restart_file_type), dimension(:), allocatable, target :: files_write ! store files that are written through write_data
500 type(domain2d), dimension(max_domains), target, save :: array_domain
501 type(domain1d), dimension(max_domains), save :: domain_x, domain_y
506 public :: open_file, open_direct_file
510 public :: file_exist, field_exist
512 public :: set_meta_global
517 public :: dimension_size
520 public :: parse_mask_table
522 public :: write_version_number
523 character(len=32), save :: filename_appendix = ''
524 
525 !--- public interface ---
526 interface string
527  module procedure string_from_integer
528  module procedure string_from_real
529 end interface
530 
531 !--- namelist interface
532 logical :: fms_netcdf_override = .true.
533 logical :: fms_netcdf_restart = .true.
534 character(len=32) :: threading_read = 'multi'
535 character(len=32) :: format = 'netcdf'
536 logical :: read_all_pe = .true.
537 character(len=64) :: iospec_ieee32 = '-N ieee_32'
538 integer :: max_files_w = 40
539 integer :: max_files_r = 40
540 integer :: dr_set_size = 10
541 logical :: read_data_bug = .false.
542 logical :: time_stamp_restart = .true.
543 logical :: print_chksum = .false.
545 logical :: debug_mask_list = .false.
546 logical :: checksum_required = .true.
547  namelist /fms_io_nml/ fms_netcdf_override, fms_netcdf_restart, &
551 
552 integer :: pack_size ! = 1 for double = 2 for float
553 
554 ! Include variable "version" to be written to log file.
555 #include<file_version.h>
556 
557 !----------
558 !ug support
561 public :: fms_io_unstructured_save_restart
562 public :: fms_io_unstructured_read
563 public :: fms_io_unstructured_get_field_size
564 public :: fms_io_unstructured_file_unit
565 public :: fms_io_unstructured_field_exist
566 
568  module procedure fms_io_unstructured_register_restart_axis_r1d
569  module procedure fms_io_unstructured_register_restart_axis_i1d
570  module procedure fms_io_unstructured_register_restart_axis_u
572 
574  module procedure fms_io_unstructured_register_restart_field_r_0d
575  module procedure fms_io_unstructured_register_restart_field_r_1d
576  module procedure fms_io_unstructured_register_restart_field_r_2d
577  module procedure fms_io_unstructured_register_restart_field_r_3d
578 #ifdef OVERLOAD_R8
579  module procedure fms_io_unstructured_register_restart_field_r8_2d
580  module procedure fms_io_unstructured_register_restart_field_r8_3d
581 #endif
582  module procedure fms_io_unstructured_register_restart_field_i_0d
583  module procedure fms_io_unstructured_register_restart_field_i_1d
584  module procedure fms_io_unstructured_register_restart_field_i_2d
586 
588  module procedure fms_io_unstructured_read_r_scalar
589  module procedure fms_io_unstructured_read_r_1d
590  module procedure fms_io_unstructured_read_r_2d
591  module procedure fms_io_unstructured_read_r_3d
592  module procedure fms_io_unstructured_read_i_scalar
593  module procedure fms_io_unstructured_read_i_1d
594  module procedure fms_io_unstructured_read_i_2d
595 end interface fms_io_unstructured_read
596 !----------
597 
598 contains
599 
600 ! <SUBROUTINE NAME="get_restart_io_mode">
601 ! <DESCRIPTION>
602 ! With the introduction of netCDF restart files, there is a need for a global
603 ! switch to turn on/off netCDF restart options in all of the modules that deal with
604 ! restart files. Here two more namelist variables (logical type) are introduced to fms_io
605 !
606 ! fms_netcdf_override
607 ! fms_netcdf_restart
608 !
609 ! because default values of both flags are .true., the default behavior of the entire model is
610 ! to use netCDF IO mode. To turn off netCDF restart, simply set fms_netcdf_restart to .false.
611 !
612 ! </DESCRIPTION>
613 ! <TEMPLATE>
614 ! call get_fms_io_mode(do_netcdf_restart)
615 ! </TEMPLATE>
616 ! <INOUT NAME="do_netcdf_restart" TYPE="logical">
617 ! This the input argument that contains the individual module setting of restart IO mode.
618 ! Upon return from this subroutine, this output argument contains the actual setting of restart IO mode
619 ! the calling module will be using
620 ! </INOUT>
621 ! </SUBROUTINE>
622 subroutine get_restart_io_mode(do_netcdf_restart)
624  logical, intent(inout) :: do_netcdf_restart
625 
626  if(fms_netcdf_override) do_netcdf_restart = fms_netcdf_restart
627 
628 end subroutine get_restart_io_mode
629 !.....................................................................
630 ! <SUBROUTINE NAME="fms_io_init">
631 ! <DESCRIPTION>
632 ! Initialize fms_io module
633 ! </DESCRIPTION>
634 ! <TEMPLATE>
635 ! call fms_io_init()
636 ! </TEMPLATE>
637 subroutine fms_io_init()
639  integer :: i, unit, io_status, logunit
640  integer, allocatable, dimension(:) :: pelist
641  real(DOUBLE_KIND) :: doubledata = 0
642  real :: realarray(4)
643  character(len=256) :: grd_file, filename
644  logical :: is_mosaic_grid
645  character(len=4096) :: attvalue
646 
647  if (module_is_initialized) return
648  call mpp_io_init()
649 
650 #ifdef INTERNAL_FILE_NML
651  read (input_nml_file, fms_io_nml, iostat=io_status)
652  if (io_status > 0) then
653  call mpp_error(fatal,'=>fms_io_init: Error reading input.nml')
654  endif
655 #else
656  call mpp_open(unit, 'input.nml',form=mpp_ascii,action=mpp_rdonly)
657  read(unit,fms_io_nml,iostat=io_status)
658  if (io_status > 0) then
659  call mpp_error(fatal,'=>fms_io_init: Error reading input.nml')
660  endif
661  call mpp_close (unit)
662 #endif
663 
664 ! take namelist options if present
665 
666 ! determine packsize
667  pack_size = size(transfer(doubledata, realarray))
668  if( pack_size .NE. 1 .AND. pack_size .NE. 2) call mpp_error(fatal,'=>fms_io_init: pack_size should be 1 or 2')
669 
670  select case (threading_read)
671  case ('multi')
672  thread_r = mpp_multi
673  case ('single')
674  thread_r = mpp_single
675  case default
676  call mpp_error(fatal,'fms_io_init: threading_read should be multi/single but you chose'//trim(threading_read))
677  end select
678 ! take namelist options if present
679 
680  select case(format)
681  case ('netcdf')
682  form=mpp_netcdf
683  case default
684  call mpp_error(fatal,'fms_io_init: only NetCDF format currently supported in fms_io')
685  end select
686 
687 ! Initially allocate files_write and files_read
689  allocate(registered_file(max_files_w))
690 
691  do i = 1, max_domains
692  array_domain(i) = null_domain2d
693  enddo
694 
695  !---- initialize module domain2d pointer ----
696  nullify (current_domain)
697 
698  !This is set here instead of at the end of the routine to prevent the read_data call below from stopping the model
699  module_is_initialized = .true.
700 
701  ! Record the version number in the log file
702  call write_version_number("FMS_IO_MOD", version)
703 
704  !--- read INPUT/grid_spec.nc to decide the value of great_circle_algorithm
705  !--- great_circle_algorithm could be true only for mosaic grid.
706  great_circle_algorithm = .false.
707  grd_file = "INPUT/grid_spec.nc"
708 
709  is_mosaic_grid = .false.
710  if (file_exist(grd_file)) then
711  if(field_exist(grd_file, 'atm_mosaic_file')) then ! coupled grid
712  is_mosaic_grid = .true.
713  else if(field_exist(grd_file, "gridfiles")) then
714  call read_data(grd_file, "gridfiles", filename, level=1)
715  grd_file = 'INPUT/'//trim(filename)
716  is_mosaic_grid = .true.
717  endif
718  endif
719 
720  if(is_mosaic_grid) then
721  if( get_global_att_value(grd_file, "great_circle_algorithm", attvalue) ) then
722  if(trim(attvalue) == "TRUE") then
723  great_circle_algorithm = .true.
724  else if(trim(attvalue) == "FALSE") then
725  great_circle_algorithm = .false.
726  else
727  call mpp_error(fatal, "fms_io(fms_io_init: value of global attribute great_circle_algorithm in file"// &
728  trim(grd_file)//" should be TRUE of FALSE")
729  endif
730  endif
731  endif
732 
733  if(great_circle_algorithm .AND. (mpp_pe() == mpp_root_pe()) ) then
734  call mpp_error(note,"fms_io_mod: great_circle algorithm will be used in the model run")
735  endif
736 
737 end subroutine fms_io_init
738 
739 ! </SUBROUTINE>
740 ! <SUBROUTINE NAME="fms_io_exit">
741 ! <DESCRIPTION>
742 ! This routine is called after ALL fields have been written to temporary files
743 ! The result NETCDF files are created here.
744 ! </DESCRIPTION>
745 ! <TEMPLATE>
746 ! call fms_io_exit
747 ! </TEMPLATE>
748 
749 subroutine fms_io_exit()
750  integer :: num_x_axes, num_y_axes, num_z_axes
751  integer :: unit
752  real, dimension(max_axis_size) :: axisdata
753  real :: tlev
754  integer, dimension(max_axes) :: id_x_axes, siz_x_axes
755  integer, dimension(max_axes) :: id_y_axes, siz_y_axes
756  integer, dimension(max_axes) :: id_z_axes, siz_z_axes
757  type(axistype), dimension(max_axes) :: x_axes, y_axes, z_axes
758  type(axistype) :: t_axes
759  type(var_type), pointer, save :: cur_var=>null()
760  integer :: i, j, k, kk
761  character(len=256) :: filename
762  character(len=10) :: axisname
763  logical :: domain_present
764  logical :: write_on_this_pe
765  type(domain2d), pointer :: io_domain =>null()
766 
767  if( .NOT.module_is_initialized )return !make sure it's only called once per PE
768 
769  do i=1,max_axis_size
770  axisdata(i) = i
771  enddo
772 
773  ! each field has an associated domain type (may be undefined).
774  ! each file only needs to write unique axes (i.e. if 2 fields share an identical axis, then only write the axis once)
775  ! unique axes are defined by the global size and domain decomposition (i.e. can support identical axis sizes with
776  ! different domain decomposition)
777 
778  do i = 1, num_files_w
779  filename = files_write(i)%name
780 
781  !--- check if any field in this file present domain.
782  domain_present = .false.
783  do j = 1, files_write(i)%nvar
784  if (files_write(i)%var(j)%domain_present) then
785  domain_present = .true.
786  exit
787  end if
788  end do
789 
790  !--- get the unique axes for all the fields.
791  num_x_axes = unique_axes(files_write(i), 1, id_x_axes, siz_x_axes, domain_x)
792  num_y_axes = unique_axes(files_write(i), 2, id_y_axes, siz_y_axes, domain_y)
793  num_z_axes = unique_axes(files_write(i), 3, id_z_axes, siz_z_axes )
794 
795  if( domain_present ) then
796  call mpp_open(unit,trim(filename),action=mpp_overwr,form=form, &
797  is_root_pe=files_write(i)%is_root_pe, domain=array_domain(files_write(i)%var(j)%domain_idx))
798  else ! global data
799  call mpp_open(unit,trim(filename),action=mpp_overwr,form=form,threading=mpp_single,&
800  fileset=mpp_single, is_root_pe=files_write(i)%is_root_pe)
801  end if
802 
803  write_on_this_pe = .false.
804  if(domain_present) then
805  io_domain => mpp_get_io_domain(array_domain(files_write(i)%var(j)%domain_idx))
806  if(associated(io_domain)) then
807  if(mpp_domain_is_tile_root_pe(io_domain)) write_on_this_pe = .true.
808  endif
809  endif
810  !--- always write out from root pe
811  if( files_write(i)%is_root_pe ) write_on_this_pe = .true.
812 
813  do j = 1, num_x_axes
814  if (j < 10) then
815  write(axisname,'(a,i1)') 'xaxis_',j
816  else
817  write(axisname,'(a,i2)') 'xaxis_',j
818  endif
819  if(id_x_axes(j) > 0) then
820  call mpp_write_meta(unit,x_axes(j),axisname,'none',axisname, &
821  data=axisdata(1:siz_x_axes(j)),domain=domain_x(id_x_axes(j)),cartesian='X')
822  else
823  call mpp_write_meta(unit,x_axes(j),axisname,'none',axisname, &
824  data=axisdata(1:siz_x_axes(j)),cartesian='X')
825  endif
826  end do
827 
828  do j = 1, num_y_axes
829  if (j < 10) then
830  write(axisname,'(a,i1)') 'yaxis_',j
831  else
832  write(axisname,'(a,i2)') 'yaxis_',j
833  endif
834  if(id_y_axes(j) > 0) then
835  call mpp_write_meta(unit,y_axes(j),axisname,'none',axisname, &
836  data=axisdata(1:siz_y_axes(j)),domain=domain_y(id_y_axes(j)),cartesian='Y')
837  else
838  call mpp_write_meta(unit,y_axes(j),axisname,'none',axisname, &
839  data=axisdata(1:siz_y_axes(j)),cartesian='Y')
840  endif
841  end do
842 
843  do j = 1, num_z_axes
844  if (j < 10) then
845  write(axisname,'(a,i1)') 'zaxis_',j
846  else
847  write(axisname,'(a,i2)') 'zaxis_',j
848  endif
849  call mpp_write_meta(unit,z_axes(j),axisname,'none',axisname, &
850  data=axisdata(1:siz_z_axes(j)),cartesian='Z')
851  end do
852 
853 
854  ! write time axis (comment out if no time axis)
855  call mpp_write_meta(unit,t_axes,&
856  'Time','time level','Time',cartesian='T')
857 
858  ! write metadata for fields
859  do j = 1, files_write(i)%nvar
860  cur_var => files_write(i)%var(j)
861  call mpp_write_meta(unit,cur_var%field, (/x_axes(cur_var%id_axes(1)), &
862  y_axes(cur_var%id_axes(2)), z_axes(cur_var%id_axes(3)), t_axes/), cur_var%name, &
863  'none',cur_var%name,pack=pack_size)
864  enddo
865 
866  ! write values for ndim of spatial axes
867  do j = 1, num_x_axes
868  call mpp_write(unit,x_axes(j))
869  enddo
870  do j = 1, num_y_axes
871  call mpp_write(unit,y_axes(j))
872  enddo
873  do j = 1, num_z_axes
874  call mpp_write(unit,z_axes(j))
875  enddo
876 
877  ! write data of each field
878  do k = 1, files_write(i)%max_ntime
879  do j = 1, files_write(i)%nvar
880  cur_var => files_write(i)%var(j)
881  tlev=k
882  ! If some fields only have one time level, we do not need to write the second level, just keep
883  ! the data missing.
884  ! If some fields only have one time level, we just write out 0 to the other level
885  if(k > cur_var%siz(4)) then
886  cur_var%buffer(:,:,:,1) = 0.0
887  kk = 1
888  else
889  kk = k
890  end if
891  if(cur_var%domain_present) then
892  call mpp_write(unit, cur_var%field,array_domain(cur_var%domain_idx), cur_var%buffer(:,:,:,kk), tlev, &
893  default_data=cur_var%default_data)
894  else if (write_on_this_pe) then
895  call mpp_write(unit, cur_var%field, cur_var%buffer(:,:,:,kk), tlev)
896  end if
897  enddo ! end j loop
898  enddo ! end k loop
899  call mpp_close(unit)
900  enddo ! end i loop
901 
902  !--- release the memory
903 
904  do i = 1, num_files_w
905  do j = 1, files_write(i)%nvar
906  deallocate(files_write(i)%var(j)%buffer)
907  end do
908  end do
909 
910  cur_var=>null()
911  module_is_initialized = .false.
912  num_files_w = 0
913  num_files_r = 0
914 
915 end subroutine fms_io_exit
916 !.....................................................................
917 ! </SUBROUTINE>
918 
919 ! <SUBROUTINE NAME="write_data">
920  !<DESCRIPTION>
921  ! This subroutine performs writing "fieldname" to file "filename". All values of "fieldname"
922  ! will be written to a temporary file. The final NETCDF file will be created only at a later step
923  ! when the user calls fms_io_exit. Therefore, make sure that fms_io_exit is called after all
924  ! fields have been written by this subroutine.
925  !</DESCRIPTION>
926 ! <TEMPLATE>
927 ! call write_data(filename, fieldname, data, domain)
928 ! </TEMPLATE>
929 ! <IN NAME="filename" TYPE="character" DIM="(*)">
930 ! File name
931 ! </IN>
932 ! <IN NAME="fieldname" TYPE="character" DIM="(*)">
933 ! Field name
934 ! </IN>
935 ! <IN NAME="data" TYPE="real">
936 ! array containing data of fieldname
937 ! </IN>
938 ! <IN NAME="domain" TYPE="domain, optional">
939 ! domain of fieldname
940 ! </IN>
941 !=================================================================================
942 subroutine write_data_i3d_new(filename, fieldname, data, domain, &
943  no_domain, position, tile_count, data_default)
945  character(len=*), intent(in) :: filename, fieldname
946  integer, dimension(:,:,:), intent(in) :: data
947  type(domain2d), intent(in), optional :: domain
948  logical, intent(in), optional :: no_domain
949  integer, intent(in), optional :: position, tile_count, data_default
950  real :: default_data
951 
952  default_data = transfer(mpp_fill_int,default_data)
953  if(present(data_default)) default_data = real(data_default)
954 
955  call write_data_3d_new(filename, fieldname, real(data), domain, &
956  no_domain, .false., position, tile_count, data_default=default_data)
957 end subroutine write_data_i3d_new
958 !.....................................................................
959 subroutine write_data_i2d_new(filename, fieldname, data, domain, &
960  no_domain, position, tile_count, data_default)
962  character(len=*), intent(in) :: filename, fieldname
963  integer, dimension(:,:), intent(in) :: data
964  type(domain2d), intent(in), optional :: domain
965  logical, intent(in), optional :: no_domain
966  integer, intent(in), optional :: position, tile_count, data_default
967  real :: default_data
968 
969  default_data = transfer(mpp_fill_int,default_data)
970  if(present(data_default)) default_data = real(data_default)
971  call write_data_2d_new(filename, fieldname, real(data), domain, &
972  no_domain, position, tile_count, data_default=default_data)
973 
974 end subroutine write_data_i2d_new
975 !.....................................................................
976 subroutine write_data_i1d_new(filename, fieldname, data, domain, &
977  no_domain, tile_count, data_default)
978  type(domain2d), intent(in), optional :: domain
979  character(len=*), intent(in) :: filename, fieldname
980  integer, dimension(:), intent(in) :: data
981  logical, intent(in), optional :: no_domain
982  integer, intent(in), optional :: tile_count, data_default
983  real :: default_data
984 
985  default_data = transfer(mpp_fill_int,default_data)
986  if(present(data_default)) default_data = real(data_default)
987  call write_data_1d_new(filename, fieldname, real(data), domain, &
988  no_domain, tile_count, data_default=default_data)
989 end subroutine write_data_i1d_new
990 !.....................................................................
991 subroutine write_data_iscalar_new(filename, fieldname, data, domain, &
992  no_domain, tile_count, data_default)
993  type(domain2d), intent(in), optional :: domain
994  character(len=*), intent(in) :: filename, fieldname
995  integer, intent(in) :: data
996  logical, intent(in), optional :: no_domain
997  integer, intent(in), optional :: tile_count, data_default
998  real :: default_data
999 
1000  default_data = transfer(mpp_fill_int,default_data)
1001  if(present(data_default)) default_data = real(data_default)
1002  call write_data_scalar_new(filename, fieldname, real(data), domain, &
1003  no_domain, tile_count, data_default=default_data)
1004 
1005 end subroutine write_data_iscalar_new
1006 !.....................................................................
1007 subroutine write_data_3d_new(filename, fieldname, data, domain, no_domain, scalar_or_1d, &
1008  position, tile_count, data_default)
1010  character(len=*), intent(in) :: filename, fieldname
1011  real, dimension(:,:,:), intent(in) :: data
1012  type(domain2d), optional, intent(in), target :: domain
1013  real, optional, intent(in) :: data_default
1014  logical, optional, intent(in) :: no_domain
1015  logical, optional, intent(in) :: scalar_or_1d
1016  integer, optional, intent(in) :: position, tile_count
1017 
1018  !--- local variables
1019  real, allocatable :: tmp_buffer(:,:,:,:)
1020  integer :: index_field ! position of the fieldname in the list of fields
1021  integer :: index_file ! position of the filename in the list of files_write
1022  logical :: append_pelist, is_no_domain, is_scalar_or_1d
1023  character(len=256) :: fname, filename2,append_string
1024  real :: default_data
1025  integer :: length, i, domain_idx
1026  integer :: ishift, jshift
1027  integer :: gxsize, gysize
1028  integer :: cxsize, cysize
1029  integer :: dxsize, dysize
1030  type(domain2d), pointer, save :: d_ptr =>null()
1031  type(var_type), pointer, save :: cur_var =>null()
1032  type(restart_file_type), pointer, save :: cur_file =>null()
1033 
1034 ! Initialize files to default values
1035  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(write_data_3d_new): need to call fms_io_init')
1036 
1037 
1038  if(PRESENT(data_default))then
1039  default_data=data_default
1040  else
1041  default_data=mpp_fill_double
1042  endif
1043 
1044  if(present(tile_count) .AND. .not. present(domain)) call mpp_error(fatal, &
1045  'fms_io write_data: when tile_count is present, domain must be present')
1046 
1047  is_scalar_or_1d = .false.
1048  if(PRESENT(scalar_or_1d)) is_scalar_or_1d = scalar_or_1d
1049 
1050  is_no_domain = .false.
1051  if (PRESENT(no_domain)) THEN
1052  is_no_domain = no_domain
1053  end if
1054 
1055  if(is_no_domain) then
1056  if(PRESENT(domain)) &
1057  call mpp_error(fatal, 'fms_io(write_data_3d_new): no_domain cannot be .true. when optional argument domain is present.')
1058  else if(PRESENT(domain))then
1059  d_ptr => domain
1060  else if (ASSOCIATED(current_domain)) then
1061  d_ptr => current_domain
1062  endif
1063 
1064  !--- remove .nc from file name
1065  length = len_trim(filename)
1066  if(filename(length-2:length) == '.nc') then
1067  filename2 = filename(1:length-3)
1068  else
1069  filename2 = filename(1:length)
1070  end if
1071 
1072  !Logical append_pelist decides whether to append the pelist_name to file name
1073  append_pelist = .false.
1074  !Append a string to the file name
1075  append_string=''
1076 
1077  !If the filename_appendix is set override the passed argument.
1078  if(len_trim(filename_appendix) > 0) then
1079  append_pelist = .true.
1080  append_string = filename_appendix
1081  endif
1082 
1083  if(append_pelist) filename2 = trim(filename2)//'.'//trim(append_string)
1084 
1085  !JWD: This is likely a temporary fix. Since fms_io needs to know tile_count,
1086  !JWD: I just don't see how the physics can remain "tile neutral"
1087  !z1l: one solution is add one more public interface called set_tile_count
1088  call get_mosaic_tile_file(filename2, fname, is_no_domain, domain, tile_count)
1089 
1090  ! Check if filename has been open or not
1091  index_file = -1
1092  do i=1,num_files_w
1093  if (trim(files_write(i)%name) == trim(fname)) then
1094  index_file = i
1095  cur_file => files_write(index_file)
1096  exit
1097  endif
1098  enddo
1099 
1100  if (index_file < 0) then
1101  if(num_files_w == max_files_w) & ! need to have bigger max_files_w
1102  call mpp_error(fatal,'fms_io(write_data_3d_new): max_files_w exceeded, increase it via fms_io_nml')
1103  ! record the file name in array files_write
1105  index_file = num_files_w
1106  cur_file => files_write(index_file)
1107  cur_file%name = trim(fname)
1108  cur_file%tile_count=1
1109  if(present(tile_count)) cur_file%tile_count = tile_count
1110  if(ASSOCIATED(d_ptr))then
1111  cur_file%is_root_pe = mpp_domain_is_tile_root_pe(d_ptr)
1112  else
1113  cur_file%is_root_pe = mpp_pe() == mpp_root_pe()
1114  endif
1115  cur_file%max_ntime = 1
1116  !-- allocate memory
1117  allocate(cur_file%var(max_fields) )
1118  cur_file%nvar = 0
1119  do i = 1, max_fields
1120  cur_file%var(i)%name = 'none'
1121  cur_file%var(i)%domain_present = .false.
1122  cur_file%var(i)%read_only = .false.
1123  cur_file%var(i)%domain_idx = -1
1124  cur_file%var(i)%is_dimvar = .false.
1125  cur_file%var(i)%position = center
1126  cur_file%var(i)%siz(:) = 0
1127  cur_file%var(i)%gsiz(:) = 0
1128  cur_file%var(i)%id_axes(:) = -1
1129  end do
1130  endif
1131 
1132  ! check if the field is new or not and get position and dimension of the field
1133  index_field = -1
1134  do i = 1, cur_file%nvar
1135  if(trim(cur_file%var(i)%name) == trim(fieldname)) then
1136  index_field = i
1137  exit
1138  end if
1139  end do
1140 
1141  if(index_field > 0) then
1142  cur_var => cur_file%var(index_field)
1143  cur_var%siz(4) = cur_var%siz(4) + 1
1144  if(cur_file%max_ntime < cur_var%siz(4) ) cur_file%max_ntime = cur_var%siz(4)
1145  ! the time level should be no larger than MAX_TIME_LEVEL_WRITE ( =20) for write_data.
1146  if( cur_var%siz(4) > max_time_level_write ) call mpp_error(fatal, 'fms_io(write_data_3d_new): ' // &
1147  'the time level of field '//trim(cur_var%name)//' in file '//trim(cur_file%name)// &
1148  ' is greater than MAX_TIME_LEVEL_WRITE(=20), increase MAX_TIME_LEVEL_WRITE or check your code')
1149  else
1150  cur_file%nvar = cur_file%nvar +1
1151  if(cur_file%nvar>max_fields) then
1152  write(error_msg,'(I3,"/",I3)') cur_file%nvar, max_fields
1153  call mpp_error(fatal,'fms_io(write_data_3d_new): max_fields exceeded, needs increasing, nvar/max_fields=' &
1154  //trim(error_msg))
1155  endif
1156  index_field = cur_file%nvar
1157  cur_var => cur_file%var(index_field)
1158  cur_var%siz(1) = size(data,1)
1159  cur_var%siz(2) = size(data,2)
1160  cur_var%siz(3) = size(data,3)
1161  cur_var%siz(4) = 1
1162  cur_var%gsiz(3) = cur_var%siz(3)
1163  cur_var%name = fieldname
1164  cur_var%default_data = default_data
1165  cur_var%ndim = 3
1166  if(present(position)) cur_var%position = position
1167 
1168  if(ASSOCIATED(d_ptr) .AND. .NOT. is_scalar_or_1d)then
1169  cur_var%domain_present = .true.
1170  domain_idx = lookup_domain(d_ptr)
1171  if(domain_idx == -1) then
1172  num_domains = num_domains + 1
1173  if(num_domains > max_domains) call mpp_error(fatal,'fms_io(write_data_3d_new), 1: max_domains exceeded,' &
1174  //' needs increasing')
1175  domain_idx = num_domains
1176  array_domain(domain_idx) = d_ptr
1177  call mpp_get_domain_components(array_domain(domain_idx), domain_x(domain_idx), domain_y(domain_idx), &
1178  tile_count=tile_count)
1179  endif
1180  cur_var%domain_idx = domain_idx
1181  call mpp_get_domain_shift ( array_domain(domain_idx), ishift, jshift, position)
1182  call mpp_get_global_domain(array_domain(domain_idx), xsize=gxsize,ysize=gysize,tile_count=tile_count)
1183  call mpp_get_compute_domain(array_domain(domain_idx), xsize = cxsize, ysize = cysize, tile_count=tile_count)
1184  call mpp_get_data_domain (array_domain(domain_idx), xsize = dxsize, ysize = dysize, tile_count=tile_count)
1185  if (ishift .NE. 0) then
1186  cxsize = cxsize+ishift; dxsize = dxsize+ishift; gxsize = gxsize + ishift
1187  end if
1188  if (jshift .NE. 0) then
1189  cysize = cysize+jshift; dysize = dysize+jshift; gysize = gysize + jshift
1190  endif
1191  if( (cur_var%siz(1) .NE. cxsize .AND. cur_var%siz(1) .NE. dxsize ) .OR. &
1192  (cur_var%siz(2) .NE. cysize .AND. cur_var%siz(2) .NE. dysize ) ) then
1193  call mpp_error(fatal, 'fms_io(write_data_3d_new): data should be on either compute domain '//&
1194  'or data domain when domain is present for field '//trim(fieldname)//' of file '//trim(filename) )
1195  end if
1196  cur_var%gsiz(1) = gxsize
1197  cur_var%gsiz(2) = gysize
1198  else
1199  cur_var%domain_present=.false.
1200  cur_var%gsiz(1) = size(data,1)
1201  cur_var%gsiz(2) = size(data,2)
1202  endif
1203  end if
1204 
1205  ! copy the data to the buffer
1206  ! if the time level is greater than the size(cur_var%buffer,4),
1207  ! need to increase the buffer size
1208 
1209  if(cur_var%siz(4) == 1) then
1210  allocate(cur_var%buffer(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3), cur_var%siz(4)) )
1211  else
1212  allocate(tmp_buffer(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3), size(cur_var%buffer,4)) )
1213  tmp_buffer = cur_var%buffer
1214  deallocate(cur_var%buffer)
1215  allocate(cur_var%buffer(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3), cur_var%siz(4)) )
1216  cur_var%buffer(:,:,:,1:size(tmp_buffer,4)) = tmp_buffer
1217  deallocate(tmp_buffer)
1218  endif
1219 
1220  cur_var%buffer(:,:,:,cur_var%siz(4)) = data ! copy current data to buffer for future write out
1221 
1222  d_ptr =>null()
1223  cur_var =>null()
1224  cur_file =>null()
1225 
1226 end subroutine write_data_3d_new
1227 ! </SUBROUTINE>
1228 
1229 !-------------------------------------------------------------------------------
1230 !
1231 ! This routine will register an integer restart file axis
1232 !
1233 !-------------------------------------------------------------------------------
1234 subroutine register_restart_axis_r1d(fileObj,filename,fieldname,data,cartesian,units,longname,sense,min,calendar)
1235  type(restart_file_type), intent(inout) :: fileObj
1236  character(len=*), intent(in) :: filename, fieldname
1237  real, intent(in), target :: data(:)
1238  character(len=*), intent(in) :: cartesian
1239  character(len=*), optional, intent(in) :: units, longname
1240  integer, optional, intent(in) :: sense
1241  real, optional, intent(in) :: min !valid min for real axis data
1242  character(len=*), optional, intent(in) :: calendar
1243 
1244  integer :: idx
1245 
1246 
1247  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_axis_r1d): need to call fms_io_init')
1248 
1249  select case(trim(cartesian))
1250  case('X')
1251  idx = xidx
1252  case('Y')
1253  idx = yidx
1254  case('Z')
1255  idx = zidx
1256  case('T')
1257  idx = tidx
1258  case('CC')
1259  idx = ccidx
1260  case default
1261  call mpp_error(fatal,'fms_io(register_restart_axis_r1d): Axis must be one of X,Y,Z,T or CC ' // &
1262  'but has value '//trim(cartesian))
1263  end select
1264  if(.not. ALLOCATED(fileobj%axes)) allocate(fileobj%axes(nidx))
1265  if(ASSOCIATED(fileobj%axes(idx)%data)) &
1266  call mpp_error(fatal,'fms_io(register_restart_axis_r1d): '//trim(cartesian)//' axis has already been defined')
1267 
1268  !Why do we do this?
1269 ! fileObj%name = filename
1270 
1271  fileobj%axes(idx)%name = fieldname
1272  fileobj%axes(idx)%data =>data
1273  fileobj%axes(idx)%cartesian = cartesian
1274  fileobj%axes(idx)%dimlen = -1 ! This is not a compressed axis
1275  if(PRESENT(units)) fileobj%axes(idx)%units = units
1276  if(PRESENT(longname)) fileobj%axes(idx)%longname = longname
1277  if(PRESENT(min)) fileobj%axes(idx)%min = min
1278  if(idx == tidx) then
1279  if(PRESENT(calendar)) fileobj%axes(idx)%calendar = trim(calendar)
1280  endif
1281  if(PRESENT(sense)) then
1282  if(idx /= zidx) call mpp_error(fatal,'fms_io(register_restart_axis_r1d): Only the Z axis may define sense; ' // &
1283  'Axis = '//trim(cartesian))
1284  if(abs(sense) /= 1) call mpp_error(fatal,'fms_io(register_restart_axis_r1d): Value of sense must be +/- 1')
1285  fileobj%axes(idx)%sense = sense
1286  endif
1287 end subroutine register_restart_axis_r1d
1288 
1289 !-------------------------------------------------------------------------------
1290 !
1291 ! This routine will register the compressed index restart file axis
1292 !
1293 !-------------------------------------------------------------------------------
1294 subroutine register_restart_axis_i1d(fileObj,filename,fieldname,data,compressed, &
1295  compressed_axis,dimlen,dimlen_name,dimlen_lname,units,longname,imin)
1296  type(restart_file_type), intent(inout) :: fileObj
1297  character(len=*), intent(in) :: filename, fieldname
1298  integer, intent(in) :: data(:)
1299  character(len=*), intent(in) :: compressed
1300  character(len=*), intent(in) :: compressed_axis !< which compressed axis (C or H)
1301  integer, intent(in) :: dimlen
1302  character(len=*), optional, intent(in) :: dimlen_name, dimlen_lname !< dimlen axis name and longname
1303  character(len=*), optional, intent(in) :: units, longname
1304  integer, optional, intent(in) :: imin !valid min for integer axis data
1305 
1306  integer :: ssize,rsize,npes
1307  integer :: idx
1308  integer, allocatable :: pelist(:)
1309  type(domain2d), pointer :: io_domain=>null()
1310 
1311 
1312  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_axis_i1d): need to call fms_io_init')
1313 
1314  select case(trim(compressed_axis))
1315  case('C')
1316  idx = cidx
1317  case('H')
1318  idx = hidx
1319  case default
1320  call mpp_error(fatal,'fms_io(register_restart_axis_r1d): Axis must be one of C or H ' // &
1321  'but has value '//trim(compressed_axis))
1322  end select
1323 
1324  if(.not. ALLOCATED(fileobj%axes)) allocate(fileobj%axes(nidx))
1325  if(ALLOCATED(fileobj%axes(idx)%idx)) &
1326  call mpp_error(fatal,'fms_io(register_restart_axis_i1d): Compressed axis ' //&
1327  trim(compressed_axis) // ' has already been defined')
1328 
1329  !Why do we do this?
1330 ! fileObj%name = filename
1331 
1332  fileobj%is_compressed = .true.
1333  fileobj%unlimited_axis = .false.
1334  fileobj%axes(idx)%name = fieldname
1335  if(ASSOCIATED(current_domain)) then
1336  fileobj%axes(idx)%domain =>current_domain
1337  io_domain =>mpp_get_io_domain(current_domain)
1338  if(.not. ASSOCIATED(io_domain)) &
1339  call mpp_error(fatal,'fms_io(register_restart_axis_i1d): The io domain must be defined')
1340  npes = mpp_get_domain_npes(io_domain)
1341  allocate(fileobj%axes(idx)%nelems(npes)); fileobj%axes(idx)%nelems = 0
1342  allocate(pelist(npes))
1343  call mpp_get_pelist(io_domain,pelist)
1344  ssize = size(data)
1345  call mpp_gather((/ssize/),fileobj%axes(idx)%nelems,pelist)
1346  rsize = sum(fileobj%axes(idx)%nelems)
1347  allocate( fileobj%axes(idx)%idx(rsize) )
1348  ! Note that the gatherV implied here is asymmetric; only root needs to know the vector of recv sizes
1349  call mpp_gather(data,ssize,fileobj%axes(idx)%idx,fileobj%axes(idx)%nelems,pelist)
1350  deallocate(pelist); io_domain=>null()
1351  else
1352  call mpp_error(fatal,'fms_io(register_restart_axis_i1d): The domain must be defined through set_domain')
1353  endif
1354  fileobj%axes(idx)%compressed = compressed
1355  fileobj%axes(idx)%dimlen = dimlen
1356  if(PRESENT(dimlen_name)) fileobj%axes(idx)%dimlen_name = dimlen_name
1357  if(PRESENT(dimlen_lname)) fileobj%axes(idx)%dimlen_lname = dimlen_lname
1358  if(PRESENT(units)) fileobj%axes(idx)%units = units
1359  if(PRESENT(longname)) fileobj%axes(idx)%longname = longname
1360  if(PRESENT(imin)) fileobj%axes(idx)%imin = imin
1361 end subroutine register_restart_axis_i1d
1362 
1363 !-------------------------------------------------------------------------------
1364 
1365 subroutine register_restart_axis_unlimited(fileObj,filename,fieldname,nelem,units,longname)
1366  type(restart_file_type), intent(inout) :: fileObj
1367  character(len=*), intent(in) :: filename, fieldname
1368  integer :: nelem ! Number of elements on rank
1369  character(len=*), optional, intent(in) :: units, longname
1370 
1371  integer :: idx,npes
1372  integer, allocatable :: pelist(:)
1373  type(domain2d), pointer :: io_domain=>null()
1374 
1375 
1376  if(.not.module_is_initialized) &
1377  call mpp_error(fatal,'fms_io(register_restart_axis_unlimited): need to call fms_io_init')
1378  idx = uidx
1379 
1380  if(.not. ALLOCATED(fileobj%axes)) allocate(fileobj%axes(nidx))
1381  if(ALLOCATED(fileobj%axes(idx)%idx)) &
1382  call mpp_error(fatal,'fms_io(register_restart_axis_unlimited): Unlimited axis has already been defined')
1383 
1384  !Why do we do this?
1385 ! fileObj%name = filename
1386 
1387  fileobj%is_compressed = .false.
1388  fileobj%unlimited_axis = .true.
1389  fileobj%axes(idx)%name = fieldname
1390  if(ASSOCIATED(current_domain)) then
1391  fileobj%axes(idx)%domain =>current_domain
1392  io_domain =>mpp_get_io_domain(current_domain)
1393  if(.not. ASSOCIATED(io_domain)) &
1394  call mpp_error(fatal,'fms_io(register_restart_axis_i1d): The io domain must be defined')
1395  npes = mpp_get_domain_npes(io_domain)
1396  allocate(fileobj%axes(idx)%nelems(npes)); fileobj%axes(idx)%nelems = 0
1397  allocate(pelist(npes))
1398  call mpp_get_pelist(io_domain,pelist)
1399  call mpp_gather((/nelem/),fileobj%axes(idx)%nelems,pelist)
1400  deallocate(pelist); io_domain=>null()
1401  else
1402  call mpp_error(fatal,'fms_io(register_restart_axis_unlimited): The domain must be defined through set_domain')
1403  endif
1404  if(PRESENT(units)) fileobj%axes(idx)%units = units
1405  if(PRESENT(longname)) fileobj%axes(idx)%longname = longname
1406 end subroutine register_restart_axis_unlimited
1407 
1408 !
1409 ! This routine is the destructor for the file object
1410 !
1411 !-------------------------------------------------------------------------------
1412 subroutine free_restart_type(fileObj)
1413  type(restart_file_type), intent(inout) :: fileobj
1414  type(meta_type),pointer :: this
1415  type(meta_type),pointer :: this_p
1416  integer :: id, n, j, k
1417 
1418  !--- remove file name from registered_file
1419  id = 0
1420  do n = 1, num_registered_files
1421  if( trim(fileobj%name) == trim(registered_file(n)) ) then
1422  id = n
1423  exit
1424  endif
1425  enddo
1426  if( id < 0) &
1427  call mpp_error(fatal, 'fms_io(free_restart_type): fileObj%name is not found in registered_files')
1428  do n = id+1, num_registered_files
1429  registered_file(n-1) = trim(registered_file(n))
1430  enddo
1433 
1434  fileobj%register_id = 0
1435  fileobj%unit = -1
1436  fileobj%name = ''
1437  fileobj%nvar = -1
1438  fileobj%natt = -1
1439  fileobj%max_ntime = -1
1440  fileobj%tile_count = -1
1441  if(ALLOCATED(fileobj%axes)) deallocate(fileobj%axes)
1442  ! deallocate all the data that restart owns
1443  do k = 1,size(fileobj%var)
1444  if (fileobj%var(k)%owns_data) then
1445  do j = 1,size(fileobj%p0dr,1)
1446  if(ASSOCIATED(fileobj%p0dr(j,k)%p)) deallocate(fileobj%p0dr(j,k)%p)
1447  if(ASSOCIATED(fileobj%p1dr(j,k)%p)) deallocate(fileobj%p1dr(j,k)%p)
1448  if(ASSOCIATED(fileobj%p2dr(j,k)%p)) deallocate(fileobj%p2dr(j,k)%p)
1449  if(ASSOCIATED(fileobj%p3dr(j,k)%p)) deallocate(fileobj%p3dr(j,k)%p)
1450  if(ASSOCIATED(fileobj%p2dr8(j,k)%p)) deallocate(fileobj%p2dr8(j,k)%p)
1451  if(ASSOCIATED(fileobj%p3dr8(j,k)%p)) deallocate(fileobj%p3dr8(j,k)%p)
1452  if(ASSOCIATED(fileobj%p0di(j,k)%p)) deallocate(fileobj%p0di(j,k)%p)
1453  if(ASSOCIATED(fileobj%p1di(j,k)%p)) deallocate(fileobj%p1di(j,k)%p)
1454  if(ASSOCIATED(fileobj%p2di(j,k)%p)) deallocate(fileobj%p2di(j,k)%p)
1455  if(ASSOCIATED(fileobj%p3di(j,k)%p)) deallocate(fileobj%p3di(j,k)%p)
1456  enddo
1457  endif
1458  enddo
1459  if(ASSOCIATED(fileobj%var)) deallocate(fileobj%var)
1460  if(ASSOCIATED(fileobj%p0dr)) deallocate(fileobj%p0dr)
1461  if(ASSOCIATED(fileobj%p1dr)) deallocate(fileobj%p1dr)
1462  if(ASSOCIATED(fileobj%p2dr)) deallocate(fileobj%p2dr)
1463  if(ASSOCIATED(fileobj%p3dr)) deallocate(fileobj%p3dr)
1464  if(ASSOCIATED(fileobj%p2dr8)) deallocate(fileobj%p2dr8)
1465  if(ASSOCIATED(fileobj%p3dr8)) deallocate(fileobj%p3dr8)
1466  if(ASSOCIATED(fileobj%p0di)) deallocate(fileobj%p0di)
1467  if(ASSOCIATED(fileobj%p1di)) deallocate(fileobj%p1di)
1468  if(ASSOCIATED(fileobj%p2di)) deallocate(fileobj%p2di)
1469  if(ASSOCIATED(fileobj%p3di)) deallocate(fileobj%p3di)
1470  if(ASSOCIATED(fileobj%first)) then
1471  this =>fileobj%first
1472  do while(associated(this%next))
1473  this =>this%next ! Find the last element
1474  enddo
1475  do while(associated(this)) ! Deallocate from the last element to the first
1476  this_p =>this%prev
1477 !!$ Gfortran on gaea does not yet support deferred length character strings
1478 !!$ deallocate(this%name)
1479  this%name='' ! Remove this line when Gfortran supports deferred length character strings
1480  if(allocated(this%rval)) deallocate(this%rval)
1481  if(allocated(this%ival)) deallocate(this%ival)
1482 !!$ Gfortran on gaea does not yet support deferred length character strings
1483 !!$ if(allocated(this%cval)) deallocate(this%cval)
1484  this%cval='' ! Remove this line when Gfortran supports deferred length character strings
1485  deallocate(this)
1486  this =>this_p
1487  enddo
1488  fileobj%first =>null()
1489  endif
1490 end subroutine free_restart_type
1491 
1492 !-------------------------------------------------------------------------------
1493 !
1494 ! The routine sets up a list of global metadata expressions for save_restart
1495 !
1496 !-------------------------------------------------------------------------------
1497 subroutine set_meta_global(fileObj, name, rval, ival, cval)
1498  type(restart_file_type), intent(inout) :: fileobj
1499  character(len=*), intent(in) :: name
1500  real, intent(in), optional :: rval(:)
1501  integer, intent(in), optional :: ival(:)
1502  character(len=*), intent(in), optional :: cval
1503  type(meta_type),pointer :: this
1504  type(meta_type),pointer :: this_n
1505 
1506  this =>fileobj%first
1507  if(associated(this))then
1508  do while(associated(this%next))
1509  this =>this%next
1510  enddo
1511  allocate(this_n); this%next =>this_n; this_n%prev =>this; this =>this_n
1512  else
1513  allocate(this)
1514  fileobj%first =>this
1515  endif
1516 
1517 ! Per mpp_write_meta_global, only one type of data can be associated with the metadata
1518 !!$ Gfortran on gaea does not yet support deferred length character strings
1519 !!$ allocate(character(len(name)) :: this%name); this%name = name
1520  this%name = name ! Remove this line when Gfortran supports deferred length character stings
1521  if(present(rval))then
1522  allocate(this%rval(size(rval))); this%rval=rval
1523  elseif(present(ival))then
1524  allocate(this%ival(size(ival))); this%ival=ival
1525  elseif(present(cval))then
1526 !!$ Gfortran on gaea does not yet support deferred length character strings
1527 !!$ allocate(character(len(cval)) :: this%cval); this%cval = cval
1528  this%cval=cval ! Remove this line when Gfortran supports deferred length character stings
1529  endif
1530 end subroutine set_meta_global
1531 
1532 
1533 !-------------------------------------------------------------------------------
1534 !
1535 ! The routine writes the global metadata
1536 !
1537 !-------------------------------------------------------------------------------
1538 subroutine write_meta_global(unit,fileObj)
1539  integer, intent(in) :: unit
1540  type(restart_file_type), intent(in) :: fileObj
1541  type(meta_type), pointer :: this
1542 
1543  this =>fileobj%first
1544  do while(associated(this))
1545  if(allocated(this%rval))then
1546  call mpp_write_meta(unit,this%name,rval=this%rval)
1547  elseif(allocated(this%ival))then
1548  call mpp_write_meta(unit,this%name,ival=this%ival)
1549 !!$ Gfortran on gaea does not yet support deferred length character strings
1550 !!$ elseif(allocated(this%cval))then
1551  elseif(len_trim(this%cval).GT.0)then ! Remove this line when Gfortran supports deferred length character stings
1552  call mpp_write_meta(unit,this%name,cval=this%cval)
1553  else
1554  call mpp_write_meta(unit,this%name)
1555  endif
1556  this =>this%next
1557  enddo
1558 end subroutine write_meta_global
1559 
1560 !-------------------------------------------------------------------------------
1561 !
1562 ! The routine will register a scalar real restart file field with one time level
1563 !
1564 !-------------------------------------------------------------------------------
1565 function register_restart_field_r0d(fileObj, filename, fieldname, data, domain, mandatory, &
1566  no_domain, position, tile_count, data_default, &
1567  longname, units, read_only, restart_owns_data)
1568  type(restart_file_type), intent(inout) :: fileobj
1569  character(len=*), intent(in) :: filename, fieldname
1570  real, intent(in), target :: data
1571  type(domain2d), optional, intent(in), target :: domain
1572  logical, optional, intent(in) :: no_domain
1573  real, optional, intent(in) :: data_default
1574  logical, optional, intent(in) :: mandatory
1575  integer, optional, intent(in) :: position, tile_count
1576  character(len=*), optional, intent(in) :: longname, units
1577  logical, optional, intent(in) :: read_only
1578  logical, optional, intent(in) :: restart_owns_data
1579  integer :: index_field
1580  integer :: register_restart_field_r0d
1581 
1582  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r0d): need to call fms_io_init')
1583  call setup_one_field(fileobj, filename, fieldname, (/1, 1, 1, 1/), index_field, domain, mandatory, &
1584  no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
1585  data_default=data_default, longname=longname, units=units, read_only=read_only,&
1586  owns_data=restart_owns_data)
1587  fileobj%p0dr(fileobj%var(index_field)%siz(4), index_field)%p => data
1588  fileobj%var(index_field)%ndim = 0
1589  register_restart_field_r0d = index_field
1590 
1591 end function register_restart_field_r0d
1592 
1593 !-------------------------------------------------------------------------------
1594 !
1595 ! The routine will register a 1-D real restart file field with one time level
1596 !
1597 !-------------------------------------------------------------------------------
1598 function register_restart_field_r1d(fileObj, filename, fieldname, data, domain, mandatory, &
1599  no_domain, position, tile_count, data_default, longname, units, &
1600  compressed_axis, read_only, restart_owns_data)
1601  type(restart_file_type), intent(inout) :: fileobj
1602  character(len=*), intent(in) :: filename, fieldname
1603  real, dimension(:), intent(in), target :: data
1604  type(domain2d), optional, intent(in), target :: domain
1605  logical, optional, intent(in) :: no_domain
1606  real, optional, intent(in) :: data_default
1607  integer, optional, intent(in) :: position, tile_count
1608  logical, optional, intent(in) :: mandatory
1609  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1610  logical, optional, intent(in) :: read_only
1611  logical, optional, intent(in) :: restart_owns_data
1612  integer :: index_field
1613  integer :: register_restart_field_r1d
1614 
1615  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r1d): need to call fms_io_init')
1616  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), 1, 1, 1/), index_field, domain, mandatory, &
1617  no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
1618  data_default=data_default, longname=longname, units=units, compressed_axis=compressed_axis, &
1619  read_only=read_only, owns_data=restart_owns_data)
1620 
1621  fileobj%p1dr(fileobj%var(index_field)%siz(4), index_field)%p => data
1622  fileobj%var(index_field)%ndim = 1
1623  register_restart_field_r1d = index_field
1624 
1625 end function register_restart_field_r1d
1626 
1627 !-------------------------------------------------------------------------------
1628 !
1629 ! The routine will register a 2-D real restart file field with one time level
1630 !
1631 !-------------------------------------------------------------------------------
1632 function register_restart_field_r2d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, &
1633  compressed, position, tile_count, data_default, longname, units, &
1634  compressed_axis, read_only, restart_owns_data)
1635  type(restart_file_type), intent(inout) :: fileobj
1636  character(len=*), intent(in) :: filename, fieldname
1637  real, dimension(:,:), intent(in), target :: data
1638  type(domain2d), optional, intent(in), target :: domain
1639  real, optional, intent(in) :: data_default
1640  logical, optional, intent(in) :: no_domain
1641  logical, optional, intent(in) :: compressed
1642  integer, optional, intent(in) :: position, tile_count
1643  logical, optional, intent(in) :: mandatory
1644  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1645  logical, optional, intent(in) :: read_only
1646  logical, optional, intent(in) :: restart_owns_data
1647  logical :: is_compressed
1648  integer :: index_field
1649  integer :: register_restart_field_r2d
1650 
1651  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r2d): need to call fms_io_init')
1652  is_compressed = .false.
1653  if(present(compressed)) is_compressed=compressed
1654  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), 1, 1/), &
1655  index_field, domain, mandatory, no_domain, is_compressed, &
1656  position, tile_count, data_default, longname, units, compressed_axis, &
1657  read_only=read_only, owns_data=restart_owns_data)
1658  fileobj%p2dr(fileobj%var(index_field)%siz(4), index_field)%p => data
1659  fileobj%var(index_field)%ndim = 2
1660  register_restart_field_r2d = index_field
1661 
1662 end function register_restart_field_r2d
1663 
1664 
1665 !-------------------------------------------------------------------------------
1666 !
1667 ! The routine will register a 3-D real restart file field with one time level
1668 !
1669 !-------------------------------------------------------------------------------
1670 function register_restart_field_r3d(fileObj, filename, fieldname, data, domain, mandatory, &
1671  no_domain, position, tile_count, data_default, longname, units, read_only, &
1672  compressed, compressed_axis, restart_owns_data)
1673  type(restart_file_type), intent(inout) :: fileobj
1674  character(len=*), intent(in) :: filename, fieldname
1675  real, dimension(:,:,:), intent(in), target :: data
1676  type(domain2d), optional, intent(in), target :: domain
1677  real, optional, intent(in) :: data_default
1678  logical, optional, intent(in) :: no_domain
1679  integer, optional, intent(in) :: position, tile_count
1680  logical, optional, intent(in) :: mandatory
1681  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1682  logical, optional, intent(in) :: read_only
1683  logical, optional, intent(in) :: compressed
1684  logical, optional, intent(in) :: restart_owns_data
1685  logical :: is_compressed
1686  integer :: index_field
1687  integer :: register_restart_field_r3d
1688 
1689  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r3d): need to call fms_io_init')
1690  if(present(compressed)) then
1691  is_compressed=compressed
1692  else
1693  is_compressed = .false.
1694  endif
1695  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), size(data,3), 1/), &
1696  index_field, domain, mandatory, no_domain, is_compressed, &
1697  position, tile_count, data_default, longname, units, compressed_axis, &
1698  read_only=read_only, owns_data=restart_owns_data)
1699  fileobj%p3dr(fileobj%var(index_field)%siz(4), index_field)%p => data
1700  fileobj%var(index_field)%ndim = 3
1701  register_restart_field_r3d = index_field
1702 
1703 end function register_restart_field_r3d
1704 
1705 
1706 #ifdef OVERLOAD_R8
1707 !-------------------------------------------------------------------------------
1708 !
1709 ! The routine will register a 2-D double_kind restart file field with one time level
1710 !
1711 !-------------------------------------------------------------------------------
1712 function register_restart_field_r2d8(fileObj, filename, fieldname, data, domain, mandatory, no_domain, &
1713  compressed, position, tile_count, data_default, longname, units, &
1714  compressed_axis, read_only, restart_owns_data)
1715  type(restart_file_type), intent(inout) :: fileobj
1716  character(len=*), intent(in) :: filename, fieldname
1717  real(DOUBLE_KIND), dimension(:,:), intent(in), target :: data
1718  type(domain2d), optional, intent(in), target :: domain
1719  real(DOUBLE_KIND), optional, intent(in) :: data_default
1720  logical, optional, intent(in) :: no_domain
1721  logical, optional, intent(in) :: compressed
1722  integer, optional, intent(in) :: position, tile_count
1723  logical, optional, intent(in) :: mandatory
1724  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1725  logical, optional, intent(in) :: read_only
1726  logical, optional, intent(in) :: restart_owns_data
1727  logical :: is_compressed
1728  integer :: index_field
1729  integer :: register_restart_field_r2d8
1730  real(FLOAT_KIND) :: data_default_r4
1731 
1732  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r2d8): need to call fms_io_init')
1733  is_compressed = .false.
1734  if(present(compressed)) is_compressed=compressed
1735  if(present(data_default)) data_default_r4=data_default
1736  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), 1, 1/), &
1737  index_field, domain, mandatory, no_domain, is_compressed, &
1738  position, tile_count, data_default_r4, longname, units, compressed_axis, &
1739  read_only=read_only, owns_data=restart_owns_data)
1740  fileobj%p2dr8(fileobj%var(index_field)%siz(4), index_field)%p => data
1741  fileobj%var(index_field)%ndim = 2
1742  register_restart_field_r2d8 = index_field
1743 
1744 end function register_restart_field_r2d8
1745 
1746 
1747 !-------------------------------------------------------------------------------
1748 !
1749 ! The routine will register a 3-D double_kind restart file field with one time level
1750 !
1751 !-------------------------------------------------------------------------------
1752 function register_restart_field_r3d8(fileObj, filename, fieldname, data, domain, mandatory, &
1753  no_domain, position, tile_count, data_default, longname, units, read_only, &
1754  compressed, compressed_axis, restart_owns_data)
1755  type(restart_file_type), intent(inout) :: fileobj
1756  character(len=*), intent(in) :: filename, fieldname
1757  real(DOUBLE_KIND), dimension(:,:,:), intent(in), target :: data
1758  type(domain2d), optional, intent(in), target :: domain
1759  real(DOUBLE_KIND), optional, intent(in) :: data_default
1760  logical, optional, intent(in) :: no_domain
1761  integer, optional, intent(in) :: position, tile_count
1762  logical, optional, intent(in) :: mandatory
1763  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1764  logical, optional, intent(in) :: read_only
1765  logical, optional, intent(in) :: compressed
1766  logical, optional, intent(in) :: restart_owns_data
1767  logical :: is_compressed
1768  integer :: index_field
1769  integer :: register_restart_field_r3d8
1770  real(FLOAT_KIND) :: data_default_r4
1771 
1772  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r3d8): need to call fms_io_init')
1773  is_compressed = .false.
1774  if(present(compressed)) is_compressed=compressed
1775  if(present(data_default)) data_default_r4=data_default
1776  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), size(data,3), 1/), &
1777  index_field, domain, mandatory, no_domain, is_compressed, &
1778  position, tile_count, data_default_r4, longname, units, compressed_axis, &
1779  read_only=read_only, owns_data=restart_owns_data)
1780  fileobj%p3dr8(fileobj%var(index_field)%siz(4), index_field)%p => data
1781  fileobj%var(index_field)%ndim = 3
1782  register_restart_field_r3d8 = index_field
1783 
1784 end function register_restart_field_r3d8
1785 #endif
1786 !-------------------------------------------------------------------------------
1787 !
1788 ! The routine will register a 4-D real restart file field with one time level
1789 !
1790 !-------------------------------------------------------------------------------
1791 function register_restart_field_r4d(fileObj, filename, fieldname, data, domain, mandatory, &
1792  no_domain, position, tile_count, data_default, longname, units, &
1793  read_only, restart_owns_data)
1794  type(restart_file_type), intent(inout) :: fileobj
1795  character(len=*), intent(in) :: filename, fieldname
1796  real, dimension(:,:,:,:), intent(in), target :: data
1797  type(domain2d), optional, intent(in), target :: domain
1798  real, optional, intent(in) :: data_default
1799  logical, optional, intent(in) :: no_domain
1800  integer, optional, intent(in) :: position, tile_count
1801  logical, optional, intent(in) :: mandatory
1802  character(len=*), optional, intent(in) :: longname, units
1803  logical, optional, intent(in) :: read_only
1804  logical, optional, intent(in) :: restart_owns_data
1805  integer :: index_field
1806  integer :: register_restart_field_r4d
1807 
1808  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_r4d): need to call fms_io_init')
1809  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), size(data,3), 1, size(data,4)/), &
1810  index_field, domain, mandatory, no_domain, .false., &
1811  position, tile_count, data_default, longname, units, &
1812  read_only=read_only, owns_data=restart_owns_data)
1813  fileobj%p4dr(fileobj%var(index_field)%siz(4), index_field)%p => data
1814  fileobj%var(index_field)%ndim = 4
1815  register_restart_field_r4d = index_field
1816 
1817 end function register_restart_field_r4d
1818 
1819 
1820 !-------------------------------------------------------------------------------
1821 !
1822 ! The routine will register a scalar integer restart file field with one time level
1823 !
1824 !-------------------------------------------------------------------------------
1825 function register_restart_field_i0d(fileObj, filename, fieldname, data, domain, mandatory, &
1826  no_domain, position, tile_count, data_default, longname, units, &
1827  read_only, restart_owns_data)
1828  type(restart_file_type), intent(inout) :: fileobj
1829  character(len=*), intent(in) :: filename, fieldname
1830  integer, intent(in), target :: data
1831  type(domain2d), optional, intent(in), target :: domain
1832  integer, optional, intent(in) :: data_default
1833  integer, optional, intent(in) :: position, tile_count
1834  logical, optional, intent(in) :: mandatory
1835  logical, optional, intent(in) :: no_domain
1836  character(len=*), optional, intent(in) :: longname, units
1837  logical, optional, intent(in) :: read_only
1838  logical, optional, intent(in) :: restart_owns_data
1839  integer :: index_field
1840  integer :: register_restart_field_i0d
1841  real :: data_default_r
1842 
1843  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_i0d): need to call fms_io_init')
1844 
1845  if (kind(data_default)/=kind(data)) call mpp_error(fatal,'fms_io(register_restart_field_i0d): data_default and data different KIND()')
1846  data_default_r = transfer(mpp_fill_int,data_default_r)
1847  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
1848 
1849  call setup_one_field(fileobj, filename, fieldname, (/1, 1, 1, 1/), index_field, domain, &
1850  mandatory, no_domain=no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
1851  data_default=data_default_r, longname=longname, units=units, &
1852  read_only=read_only, owns_data=restart_owns_data)
1853 
1854  fileobj%p0di(fileobj%var(index_field)%siz(4), index_field)%p => data
1855  fileobj%var(index_field)%ndim = 0
1856  register_restart_field_i0d = index_field
1857 
1858 end function register_restart_field_i0d
1859 
1860 !-------------------------------------------------------------------------------
1861 !
1862 ! The routine will register a 1-D integer restart file field with one time level
1863 !
1864 !-------------------------------------------------------------------------------
1865 function register_restart_field_i1d(fileObj, filename, fieldname, data, domain, mandatory, &
1866  no_domain, position, tile_count, data_default, longname, units, &
1867  compressed_axis, read_only, restart_owns_data)
1868  type(restart_file_type), intent(inout) :: fileobj
1869  character(len=*), intent(in) :: filename, fieldname
1870  integer, dimension(:), intent(in), target :: data
1871  type(domain2d), optional, intent(in), target :: domain
1872  integer, optional, intent(in) :: data_default
1873  integer, optional, intent(in) :: position, tile_count
1874  logical, optional, intent(in) :: mandatory
1875  logical, optional, intent(in) :: no_domain
1876  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1877  logical, optional, intent(in) :: read_only
1878  logical, optional, intent(in) :: restart_owns_data
1879  integer :: index_field
1880  integer :: register_restart_field_i1d
1881  real :: data_default_r
1882 
1883  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_i1d): need to call fms_io_init')
1884 
1885  if (kind(data_default)/=kind(data)) call mpp_error(fatal,'fms_io(register_restart_field_i1d): data_default and data different KIND()')
1886  data_default_r = transfer(mpp_fill_int,data_default_r)
1887  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
1888 
1889  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), 1, 1, 1/), index_field, domain, &
1890  mandatory, no_domain=no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
1891  data_default=data_default_r, longname=longname, units=units, compressed_axis=compressed_axis, &
1892  read_only=read_only, owns_data=restart_owns_data)
1893  fileobj%p1di(fileobj%var(index_field)%siz(4), index_field)%p => data
1894  fileobj%var(index_field)%ndim = 1
1895  register_restart_field_i1d = index_field
1896 
1897 end function register_restart_field_i1d
1898 
1899 
1900 !-------------------------------------------------------------------------------
1901 !
1902 ! The routine will register a 2-D real restart file field with one time level
1903 !
1904 !-------------------------------------------------------------------------------
1905 function register_restart_field_i2d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, &
1906  compressed, position, tile_count, data_default, longname, units, &
1907  compressed_axis, read_only, restart_owns_data)
1908  type(restart_file_type), intent(inout) :: fileobj
1909  character(len=*), intent(in) :: filename, fieldname
1910  integer, dimension(:,:), intent(in), target :: data
1911  type(domain2d), optional, intent(in), target :: domain
1912  integer, optional, intent(in) :: data_default
1913  logical, optional, intent(in) :: no_domain
1914  logical, optional, intent(in) :: compressed
1915  integer, optional, intent(in) :: position, tile_count
1916  logical, optional, intent(in) :: mandatory
1917  character(len=*), optional, intent(in) :: longname, units, compressed_axis
1918  logical, optional, intent(in) :: read_only
1919  logical, optional, intent(in) :: restart_owns_data
1920  logical :: is_compressed
1921  integer :: index_field
1922  integer :: register_restart_field_i2d
1923  real :: data_default_r
1924 
1925  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_i2d): need to call fms_io_init')
1926  is_compressed = .false.
1927  if(present(compressed)) is_compressed=compressed
1928 
1929  if (kind(data_default)/=kind(data)) call mpp_error(fatal,'fms_io(register_restart_field_i2d): data_default and data different KIND()')
1930  data_default_r = transfer(mpp_fill_int,data_default_r)
1931  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
1932 
1933  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), 1, 1/), &
1934  index_field, domain, mandatory, no_domain, is_compressed, &
1935  position, tile_count, data_default_r, longname, units, compressed_axis, &
1936  read_only=read_only, owns_data=restart_owns_data)
1937  fileobj%p2di(fileobj%var(index_field)%siz(4), index_field)%p => data
1938  fileobj%var(index_field)%ndim = 2
1939  register_restart_field_i2d = index_field
1940 
1941 end function register_restart_field_i2d
1942 
1943 !-------------------------------------------------------------------------------
1944 !
1945 ! The routine will register a 3-D real restart file field with one time level
1946 !
1947 !-------------------------------------------------------------------------------
1948 function register_restart_field_i3d(fileObj, filename, fieldname, data, domain, mandatory, &
1949  no_domain, position, tile_count, data_default, longname, units, &
1950  read_only, restart_owns_data)
1951  type(restart_file_type), intent(inout) :: fileobj
1952  character(len=*), intent(in) :: filename, fieldname
1953  integer, dimension(:,:,:), intent(in), target :: data
1954  type(domain2d), optional, intent(in), target :: domain
1955  integer, optional, intent(in) :: data_default
1956  logical, optional, intent(in) :: no_domain
1957  integer, optional, intent(in) :: position, tile_count
1958  logical, optional, intent(in) :: mandatory
1959  character(len=*), optional, intent(in) :: longname, units
1960  logical, optional, intent(in) :: read_only
1961  logical, optional, intent(in) :: restart_owns_data
1962  integer :: index_field
1963  integer :: register_restart_field_i3d
1964  real :: data_default_r
1965 
1966  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_field_i3d): need to call fms_io_init')
1967 
1968  if (kind(data_default)/=kind(data)) call mpp_error(fatal,'fms_io(register_restart_field_i3d): data_default and data different KIND()')
1969  data_default_r = transfer(mpp_fill_int,data_default_r)
1970  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
1971 
1972  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), size(data,3), 1/), &
1973  index_field, domain, mandatory, no_domain, .false., &
1974  position, tile_count, data_default_r, longname, units, &
1975  read_only=read_only, owns_data=restart_owns_data)
1976  fileobj%p3di(fileobj%var(index_field)%siz(4), index_field)%p => data
1977  fileobj%var(index_field)%ndim = 3
1978  register_restart_field_i3d = index_field
1979 
1980 end function register_restart_field_i3d
1981 
1982 !-------------------------------------------------------------------------------
1983 !
1984 ! The routine will register a scalar real restart file field with two time level
1985 !
1986 !-------------------------------------------------------------------------------
1987 function register_restart_field_r0d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
1988  no_domain, position, tile_count, data_default, longname, units, read_only)
1989  type(restart_file_type), intent(inout) :: fileobj
1990  character(len=*), intent(in) :: filename, fieldname
1991  real, intent(in), target :: data1, data2
1992  type(domain2d), optional, intent(in), target :: domain
1993  real, optional, intent(in) :: data_default
1994  integer, optional, intent(in) :: position, tile_count
1995  logical, optional, intent(in) :: mandatory
1996  logical, optional, intent(in) :: no_domain
1997  character(len=*), optional, intent(in) :: longname, units
1998  logical, optional, intent(in) :: read_only
1999  integer :: index_field
2001 
2002  if(.not.module_is_initialized) call mpp_error(fatal, &
2003  'fms_io(register_restart_field_r0d_2level): need to call fms_io_init')
2004  call setup_one_field(fileobj, filename, fieldname, (/1, 1, 1, 2/), index_field, domain, &
2005  mandatory, no_domain=no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
2006  data_default=data_default, longname=longname, units=units, read_only=read_only)
2007  fileobj%p0dr(1, index_field)%p => data1
2008  fileobj%p0dr(2, index_field)%p => data2
2009  fileobj%var(index_field)%ndim = 0
2010  register_restart_field_r0d_2level = index_field
2011 
2013 
2014 !-------------------------------------------------------------------------------
2015 !
2016 ! The routine will register a 1-D real restart file field with two time level
2017 !
2018 !-------------------------------------------------------------------------------
2019 function register_restart_field_r1d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2020  no_domain, position, tile_count, data_default, longname, units, read_only)
2021  type(restart_file_type), intent(inout) :: fileobj
2022  character(len=*), intent(in) :: filename, fieldname
2023  real, dimension(:), intent(in), target :: data1, data2
2024  type(domain2d), optional, intent(in), target :: domain
2025  real, optional, intent(in) :: data_default
2026  integer, optional, intent(in) :: position, tile_count
2027  logical, optional, intent(in) :: mandatory
2028  logical, optional, intent(in) :: no_domain
2029  character(len=*), optional, intent(in) :: longname, units
2030  logical, optional, intent(in) :: read_only
2031  integer :: index_field
2033 
2034  if(.not.module_is_initialized) call mpp_error(fatal, &
2035  'fms_io(register_restart_field_r1d_2level): need to call fms_io_init')
2036  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), 1, 1, 2/), index_field, domain, &
2037  mandatory, no_domain=no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
2038  data_default=data_default, longname=longname, units=units, read_only=read_only)
2039  fileobj%p1dr(1, index_field)%p => data1
2040  fileobj%p1dr(2, index_field)%p => data2
2041  fileobj%var(index_field)%ndim = 1
2042  register_restart_field_r1d_2level = index_field
2043 
2044  return
2045 
2047 
2048 !-------------------------------------------------------------------------------
2049 !
2050 ! The routine will register a 3-D real restart file field with two time level
2051 !
2052 !-------------------------------------------------------------------------------
2053 function register_restart_field_r2d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2054  no_domain, position, tile_count, data_default, longname, units, read_only)
2055  type(restart_file_type), intent(inout) :: fileobj
2056  character(len=*), intent(in) :: filename, fieldname
2057  real, dimension(:,:), intent(in), target :: data1, data2
2058  type(domain2d), optional, intent(in), target :: domain
2059  real, optional, intent(in) :: data_default
2060  logical, optional, intent(in) :: no_domain
2061  integer, optional, intent(in) :: position, tile_count
2062  logical, optional, intent(in) :: mandatory
2063  character(len=*), optional, intent(in) :: longname, units
2064  logical, optional, intent(in) :: read_only
2065  integer :: index_field
2067 
2068  if(.not.module_is_initialized) call mpp_error(fatal, &
2069  'fms_io(register_restart_field_r2d_2level): need to call fms_io_init')
2070  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), size(data1,2), 1, 2/), &
2071  index_field, domain, mandatory, no_domain, .false., &
2072  position, tile_count, data_default, longname, units, read_only=read_only)
2073  fileobj%p2dr(1, index_field)%p => data1
2074  fileobj%p2dr(2, index_field)%p => data2
2075  fileobj%var(index_field)%ndim = 2
2076  register_restart_field_r2d_2level = index_field
2077 
2078  return
2079 
2081 
2082 !-------------------------------------------------------------------------------
2083 !
2084 ! The routine will register a 3-D real restart file field with two time level
2085 !
2086 !-------------------------------------------------------------------------------
2087 function register_restart_field_r3d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2088  no_domain, position, tile_count, data_default, longname, units, read_only)
2089  type(restart_file_type), intent(inout) :: fileobj
2090  character(len=*), intent(in) :: filename, fieldname
2091  real, dimension(:,:,:), intent(in), target :: data1, data2
2092  type(domain2d), optional, intent(in), target :: domain
2093  real, optional, intent(in) :: data_default
2094  logical, optional, intent(in) :: no_domain
2095  integer, optional, intent(in) :: position, tile_count
2096  logical, optional, intent(in) :: mandatory
2097  character(len=*), optional, intent(in) :: longname, units
2098  logical, optional, intent(in) :: read_only
2099  integer :: index_field
2101 
2102  if(.not.module_is_initialized) call mpp_error(fatal, &
2103  'fms_io(register_restart_field_r3d_2level): need to call fms_io_init')
2104  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), size(data1,2), size(data1,3), 2/), &
2105  index_field, domain, mandatory, no_domain, .false., &
2106  position, tile_count, data_default, longname, units, read_only=read_only)
2107  fileobj%p3dr(1, index_field)%p => data1
2108  fileobj%p3dr(2, index_field)%p => data2
2109  fileobj%var(index_field)%ndim = 3
2110  register_restart_field_r3d_2level = index_field
2111 
2112  return
2113 
2115 
2116 #ifdef OVERLOAD_R8
2117 !-------------------------------------------------------------------------------
2118 !
2119 ! The routine will register a 2-D double_kind restart file field with two time level
2120 !
2121 !-------------------------------------------------------------------------------
2122 function register_restart_field_r2d8_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2123  no_domain, position, tile_count, data_default, longname, units, read_only)
2124  type(restart_file_type), intent(inout) :: fileobj
2125  character(len=*), intent(in) :: filename, fieldname
2126  real(DOUBLE_KIND), dimension(:,:), intent(in), target :: data1, data2
2127  type(domain2d), optional, intent(in), target :: domain
2128  real, optional, intent(in) :: data_default
2129  logical, optional, intent(in) :: no_domain
2130  integer, optional, intent(in) :: position, tile_count
2131  logical, optional, intent(in) :: mandatory
2132  character(len=*), optional, intent(in) :: longname, units
2133  logical, optional, intent(in) :: read_only
2134  integer :: index_field
2135  integer :: register_restart_field_r2d8_2level
2136 
2137  if(.not.module_is_initialized) call mpp_error(fatal, &
2138  'fms_io(register_restart_field_r2d_2level): need to call fms_io_init')
2139  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), size(data1,2), 1, 2/), &
2140  index_field, domain, mandatory, no_domain, .false., &
2141  position, tile_count, data_default, longname, units, read_only=read_only)
2142  fileobj%p2dr8(1, index_field)%p => data1
2143  fileobj%p2dr8(2, index_field)%p => data2
2144  fileobj%var(index_field)%ndim = 2
2145  register_restart_field_r2d8_2level = index_field
2146 
2147  return
2148 
2149 end function register_restart_field_r2d8_2level
2150 
2151 !-------------------------------------------------------------------------------
2152 !
2153 ! The routine will register a 3-D double_kind restart file field with two time level
2154 !
2155 !-------------------------------------------------------------------------------
2156 function register_restart_field_r3d8_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2157  no_domain, position, tile_count, data_default, longname, units, read_only)
2158  type(restart_file_type), intent(inout) :: fileobj
2159  character(len=*), intent(in) :: filename, fieldname
2160  real(DOUBLE_KIND), dimension(:,:,:), intent(in), target :: data1, data2
2161  type(domain2d), optional, intent(in), target :: domain
2162  real, optional, intent(in) :: data_default
2163  logical, optional, intent(in) :: no_domain
2164  integer, optional, intent(in) :: position, tile_count
2165  logical, optional, intent(in) :: mandatory
2166  character(len=*), optional, intent(in) :: longname, units
2167  logical, optional, intent(in) :: read_only
2168  integer :: index_field
2169  integer :: register_restart_field_r3d8_2level
2170 
2171  if(.not.module_is_initialized) call mpp_error(fatal, &
2172  'fms_io(register_restart_field_r3d_2level): need to call fms_io_init')
2173  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), size(data1,2), size(data1,3), 2/), &
2174  index_field, domain, mandatory, no_domain, .false., &
2175  position, tile_count, data_default, longname, units, read_only=read_only)
2176  fileobj%p3dr8(1, index_field)%p => data1
2177  fileobj%p3dr8(2, index_field)%p => data2
2178  fileobj%var(index_field)%ndim = 3
2179  register_restart_field_r3d8_2level = index_field
2180 
2181  return
2182 
2183 end function register_restart_field_r3d8_2level
2184 #endif
2185 
2186 !-------------------------------------------------------------------------------
2187 !
2188 ! The routine will register a scalar integer restart file field with two time level
2189 !
2190 !-------------------------------------------------------------------------------
2191 function register_restart_field_i0d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2192  no_domain, position, tile_count, data_default, longname, units, read_only)
2193  type(restart_file_type), intent(inout) :: fileobj
2194  character(len=*), intent(in) :: filename, fieldname
2195  integer, intent(in), target :: data1, data2
2196  type(domain2d), optional, intent(in), target :: domain
2197  integer, optional, intent(in) :: data_default
2198  integer, optional, intent(in) :: position, tile_count
2199  logical, optional, intent(in) :: mandatory
2200  logical, optional, intent(in) :: no_domain
2201  character(len=*), optional, intent(in) :: longname, units
2202  logical, optional, intent(in) :: read_only
2203  integer :: index_field
2205  real :: data_default_r
2206 
2207  if(.not.module_is_initialized) call mpp_error(fatal, &
2208  'fms_io(register_restart_field_i0d_2level): need to call fms_io_init')
2209 
2210  if (kind(data_default)/=kind(data1)) call mpp_error(fatal,'fms_io(register_restart_field_i0d_2level): data_default and data1 different KIND()')
2211  if (kind(data_default)/=kind(data2)) call mpp_error(fatal,'fms_io(register_restart_field_i0d_2level): data_default and data2 different KIND()')
2212  data_default_r = transfer(mpp_fill_int,data_default_r)
2213  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
2214 
2215  call setup_one_field(fileobj, filename, fieldname, (/1, 1, 1, 2/), index_field, domain, &
2216  mandatory, no_domain=no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
2217  data_default=data_default_r, longname=longname, units=units, read_only=read_only)
2218  fileobj%p0di(1, index_field)%p => data1
2219  fileobj%p0di(2, index_field)%p => data2
2220  fileobj%var(index_field)%ndim = 0
2221  register_restart_field_i0d_2level = index_field
2222 
2223  return
2224 
2226 
2227 !-------------------------------------------------------------------------------
2228 !
2229 ! The routine will register a 1-D integer restart file field with two time level
2230 !
2231 !-------------------------------------------------------------------------------
2232 function register_restart_field_i1d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2233  no_domain, position, tile_count, data_default, longname, units, read_only)
2234  type(restart_file_type), intent(inout) :: fileobj
2235  character(len=*), intent(in) :: filename, fieldname
2236  integer, dimension(:), intent(in), target :: data1, data2
2237  type(domain2d), optional, intent(in), target :: domain
2238  integer, optional, intent(in) :: data_default
2239  integer, optional, intent(in) :: position, tile_count
2240  logical, optional, intent(in) :: mandatory
2241  logical, optional, intent(in) :: no_domain
2242  character(len=*), optional, intent(in) :: longname, units
2243  logical, optional, intent(in) :: read_only
2244  integer :: index_field
2246  real :: data_default_r
2247 
2248  if(.not.module_is_initialized) call mpp_error(fatal, &
2249  'fms_io(register_restart_field_i1d_2level): need to call fms_io_init')
2250 
2251  if (kind(data_default)/=kind(data1)) call mpp_error(fatal,'fms_io(register_restart_field_i1d_2level): data_default and data1 different KIND()')
2252  if (kind(data_default)/=kind(data2)) call mpp_error(fatal,'fms_io(register_restart_field_i1d_2level): data_default and data2 different KIND()')
2253  data_default_r = transfer(mpp_fill_int,data_default_r)
2254  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
2255 
2256  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), 1, 1, 2/), index_field, domain, &
2257  mandatory, no_domain=no_domain, scalar_or_1d=.true., position=position, tile_count=tile_count, &
2258  data_default=data_default_r, longname=longname, units=units, read_only=read_only)
2259  fileobj%p1di(1, index_field)%p => data1
2260  fileobj%p1di(2, index_field)%p => data2
2261  fileobj%var(index_field)%ndim = 1
2262  register_restart_field_i1d_2level = index_field
2263 
2264  return
2265 
2267 
2268 !-------------------------------------------------------------------------------
2269 !
2270 ! The routine will register a 2-D integer restart file field with two time level
2271 !
2272 !-------------------------------------------------------------------------------
2273 function register_restart_field_i2d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2274  no_domain, position, tile_count, data_default, longname, units, read_only)
2275  type(restart_file_type), intent(inout) :: fileobj
2276  character(len=*), intent(in) :: filename, fieldname
2277  integer, dimension(:,:), intent(in), target :: data1, data2
2278  type(domain2d), optional, intent(in), target :: domain
2279  integer, optional, intent(in) :: data_default
2280  logical, optional, intent(in) :: no_domain
2281  integer, optional, intent(in) :: position, tile_count
2282  logical, optional, intent(in) :: mandatory
2283  character(len=*), optional, intent(in) :: longname, units
2284  logical, optional, intent(in) :: read_only
2285  integer :: index_field
2287  real :: data_default_r
2288 
2289  if(.not.module_is_initialized) call mpp_error(fatal, &
2290  'fms_io(register_restart_field_i2d_2level): need to call fms_io_init')
2291 
2292  if (kind(data_default)/=kind(data1)) call mpp_error(fatal,'fms_io(register_restart_field_i2d_2level): data_default and data1 different KIND()')
2293  if (kind(data_default)/=kind(data2)) call mpp_error(fatal,'fms_io(register_restart_field_i2d_2level): data_default and data2 different KIND()')
2294  data_default_r = transfer(mpp_fill_int,data_default_r)
2295  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
2296 
2297  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), size(data1,2), 1, 2/), &
2298  index_field, domain, mandatory, no_domain, .false., &
2299  position, tile_count, data_default_r, longname, units, read_only=read_only)
2300  fileobj%p2di(1, index_field)%p => data1
2301  fileobj%p2di(2, index_field)%p => data2
2302  fileobj%var(index_field)%ndim = 2
2303  register_restart_field_i2d_2level = index_field
2304 
2305  return
2306 
2308 
2309 !-------------------------------------------------------------------------------
2310 !
2311 ! The routine will register a 3-D integer restart file field with two time level
2312 !
2313 !-------------------------------------------------------------------------------
2314 function register_restart_field_i3d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, &
2315  no_domain, position, tile_count, data_default, longname, units, read_only)
2316  type(restart_file_type), intent(inout) :: fileobj
2317  character(len=*), intent(in) :: filename, fieldname
2318  integer, dimension(:,:,:), intent(in), target :: data1, data2
2319  type(domain2d), optional, intent(in), target :: domain
2320  integer, optional, intent(in) :: data_default
2321  logical, optional, intent(in) :: no_domain
2322  integer, optional, intent(in) :: position, tile_count
2323  logical, optional, intent(in) :: mandatory
2324  character(len=*), optional, intent(in) :: longname, units
2325  logical, optional, intent(in) :: read_only
2326  integer :: index_field
2328  real :: data_default_r
2329 
2330  if(.not.module_is_initialized) call mpp_error(fatal, &
2331  'fms_io(register_restart_field_i3d_2level): need to call fms_io_init')
2332 
2333  if (kind(data_default)/=kind(data1)) call mpp_error(fatal,'fms_io(register_restart_field_i3d_2level): data_default and data1 different KIND()')
2334  if (kind(data_default)/=kind(data2)) call mpp_error(fatal,'fms_io(register_restart_field_i3d_2level): data_default and data2 different KIND()')
2335  data_default_r = transfer(mpp_fill_int,data_default_r)
2336  if (present(data_default)) data_default_r = transfer(data_default ,data_default_r)
2337 
2338  call setup_one_field(fileobj, filename, fieldname, (/size(data1,1), size(data1,2), size(data1,3), 2/), &
2339  index_field, domain, mandatory, no_domain, .false., &
2340  position, tile_count, data_default_r, longname, units, read_only=read_only)
2341  fileobj%p3di(1, index_field)%p => data1
2342  fileobj%p3di(2, index_field)%p => data2
2343  fileobj%var(index_field)%ndim = 3
2344  register_restart_field_i3d_2level = index_field
2345 
2346  return
2347 
2349 
2350 !-------------------------------------------------------------------------------
2351 !
2352 ! The routine will register a 2-D real for a generic region defined
2353 ! by the global_size variable.
2354 !
2355 !-------------------------------------------------------------------------------
2356 function register_restart_region_r2d (fileObj, filename, fieldname, data, indices, global_size, &
2357  pelist, is_root_pe, longname, units, position, &
2358  x_halo, y_halo, ishift, jshift, read_only, mandatory)
2359  type(restart_file_type), intent(inout) :: fileobj
2360  character(len=*), intent(in) :: filename, fieldname
2361  real, dimension(:,:), intent(in), target :: data
2362  integer, dimension(:), intent(in) :: indices, global_size, pelist
2363  logical, intent(in) :: is_root_pe
2364  character(len=*), optional, intent(in) :: longname, units
2365  integer, optional, intent(in) :: position, x_halo, y_halo, ishift, jshift
2366  logical, optional, intent(in) :: read_only
2367  logical, optional, intent(in) :: mandatory
2368  integer :: index_field, l_position
2369  integer :: register_restart_region_r2d
2370 
2371  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_region_r2d): need to call fms_io_init')
2372  if ((is_root_pe) .and. (.not.any(mpp_pe().eq.pelist))) call mpp_error(fatal, &
2373  'fms_io(register_restart_region_r2d) designated root_pe is not a member of pelist')
2374  l_position = center
2375  if (present(position)) l_position = position
2376  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), 1, 1/), &
2377  index_field, no_domain=.true., position=l_position, longname=longname, units=units, &
2378  read_only=read_only, mandatory=mandatory)
2379  fileobj%p2dr(fileobj%var(index_field)%siz(4), index_field)%p => data
2380  fileobj%var(index_field)%ndim = 2
2381  fileobj%var(index_field)%is = indices(1)
2382  fileobj%var(index_field)%ie = indices(2)
2383  fileobj%var(index_field)%js = indices(3)
2384  fileobj%var(index_field)%je = indices(4)
2385  fileobj%var(index_field)%gsiz(1) = global_size(1)
2386  fileobj%var(index_field)%gsiz(2) = global_size(2)
2387  fileobj%is_root_pe = is_root_pe
2388  fileobj%var(index_field)%x_halo = 0
2389  fileobj%var(index_field)%y_halo = 0
2390  fileobj%var(index_field)%ishift = 0
2391  fileobj%var(index_field)%jshift = 0
2392  if (present(x_halo)) fileobj%var(index_field)%x_halo = x_halo
2393  if (present(y_halo)) fileobj%var(index_field)%y_halo = y_halo
2394  if (present(ishift)) fileobj%var(index_field)%ishift = ishift
2395  if (present(jshift)) fileobj%var(index_field)%jshift = jshift
2396  if (allocated(fileobj%var(index_field)%pelist)) deallocate(fileobj%var(index_field)%pelist)
2397  if (allocated(fileobj%var(index_field)%pelist)) deallocate(fileobj%var(index_field)%pelist)
2398  allocate(fileobj%var(index_field)%pelist(size(pelist)))
2399  fileobj%var(index_field)%pelist = pelist
2400  register_restart_region_r2d = index_field
2401 
2402  return
2403 end function register_restart_region_r2d
2404 
2405 !-------------------------------------------------------------------------------
2406 !
2407 ! The routine will register a 3-D real for a generic region defined
2408 ! by the global_size variable.
2409 !
2410 !-------------------------------------------------------------------------------
2411 function register_restart_region_r3d (fileObj, filename, fieldname, data, indices, global_size, &
2412  pelist, is_root_pe, longname, units, position, &
2413  x_halo, y_halo, ishift, jshift, read_only, mandatory)
2414  type(restart_file_type), intent(inout) :: fileobj
2415  character(len=*), intent(in) :: filename, fieldname
2416  real, dimension(:,:,:), intent(in), target :: data
2417  integer, dimension(:), intent(in) :: indices, global_size, pelist
2418  logical, intent(in) :: is_root_pe
2419  character(len=*), optional, intent(in) :: longname, units
2420  logical, optional, intent(in) :: read_only
2421  integer, optional, intent(in) :: position, x_halo, y_halo, ishift, jshift
2422  logical, optional, intent(in) :: mandatory
2423  integer :: index_field, l_position
2424  integer :: register_restart_region_r3d
2425 
2426  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(register_restart_region_r3d): need to call fms_io_init')
2427  if ((is_root_pe) .and. (.not.any(mpp_pe().eq.pelist))) call mpp_error(fatal, &
2428  'fms_io(register_restart_region_r3d) designated root_pe is not a member of pelist')
2429  l_position = center
2430  if (present(position)) l_position = position
2431  call setup_one_field(fileobj, filename, fieldname, (/size(data,1), size(data,2), size(data,3), 1/), &
2432  index_field, no_domain=.true., position=l_position, longname=longname, units=units, &
2433  read_only=read_only, mandatory=mandatory)
2434  fileobj%p3dr(fileobj%var(index_field)%siz(4), index_field)%p => data
2435  fileobj%var(index_field)%ndim = 3
2436  fileobj%var(index_field)%is = indices(1)
2437  fileobj%var(index_field)%ie = indices(2)
2438  fileobj%var(index_field)%js = indices(3)
2439  fileobj%var(index_field)%je = indices(4)
2440  fileobj%var(index_field)%gsiz(1) = global_size(1)
2441  fileobj%var(index_field)%gsiz(2) = global_size(2)
2442  fileobj%var(index_field)%gsiz(3) = global_size(3)
2443  fileobj%is_root_pe = is_root_pe
2444  fileobj%var(index_field)%x_halo = 0
2445  fileobj%var(index_field)%y_halo = 0
2446  fileobj%var(index_field)%ishift = 0
2447  fileobj%var(index_field)%jshift = 0
2448  if (present(x_halo)) fileobj%var(index_field)%x_halo = x_halo
2449  if (present(y_halo)) fileobj%var(index_field)%y_halo = y_halo
2450  if (present(ishift)) fileobj%var(index_field)%ishift = ishift
2451  if (present(jshift)) fileobj%var(index_field)%jshift = jshift
2452  if (allocated(fileobj%var(index_field)%pelist)) deallocate(fileobj%var(index_field)%pelist)
2453  allocate(fileobj%var(index_field)%pelist(size(pelist)))
2454  fileobj%var(index_field)%pelist = pelist
2455  register_restart_region_r3d = index_field
2456 
2457  return
2458 end function register_restart_region_r3d
2459 
2460 !-------------------------------------------------------------------------------
2461 !
2462 ! saves all registered variables to restart files. Those variables are set
2463 ! through register_restart_field
2464 !
2465 !-------------------------------------------------------------------------------
2466 subroutine save_restart(fileObj, time_stamp, directory, append, time_level)
2467  type(restart_file_type), intent(inout) :: fileobj
2468  character(len=*), intent(in), optional :: directory
2469  character(len=*), intent(in), optional :: time_stamp
2470  ! Arguments:
2471  ! (in) directory - The directory where the restart file goes.
2472  ! (in) time_stamp - character format of the time of this restart file.
2473  logical, intent(in), optional :: append
2474  real, intent(in), optional :: time_level
2475  character(len=256) :: dir
2476  character(len=80) :: restartname ! The restart file name (no dir).
2477  character(len=336) :: restartpath ! The restart file path (dir/file).
2478 
2479  ! This approach is taken rather than interface overloading in order to preserve
2480  ! use of the register_restart_field infrastructure
2481 
2482  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(save_restart): " // &
2483  "restart_file_type data must be initialized by calling register_restart_field before using it")
2484 
2485  dir = "RESTART"
2486  if(present(directory)) dir = directory
2487 
2488  restartname = fileobj%name
2489  if(time_stamp_restart) then
2490  if (PRESENT(time_stamp)) then
2491  if(len_trim(restartname)+len_trim(time_stamp) > 79) call mpp_error(fatal, "fms_io(save_restart): " // &
2492  "Length of restart file name + time_stamp is greater than allowed character length of 79")
2493  restartname = trim(time_stamp)//"."//trim(restartname)
2494  endif
2495  end if
2496  if(len_trim(dir) > 0) then
2497  if(len_trim(dir)+len_trim(restartname) > 335) call mpp_error(fatal, "fms_io(save_restart): " // &
2498  "Length of full restart path + file name is greater than allowed character length of 355")
2499  restartpath = trim(dir)//"/"// trim(restartname)
2500  else
2501  restartpath = trim(restartname)
2502  end if
2503 
2504  if(fileobj%is_compressed .AND. ALLOCATED(fileobj%axes)) then
2505  ! fileObj%axes must also be allocated if the file contains compressed axes
2506  ! But will this always be true in the future?
2507  call save_compressed_restart(fileobj,restartpath,append,time_level)
2508  elseif(fileobj%unlimited_axis .AND. ALLOCATED(fileobj%axes)) then
2509  call save_unlimited_axis_restart(fileobj,restartpath)
2510  else
2511  call save_default_restart(fileobj,restartpath)
2512  endif
2513 
2514  if(print_chksum) call write_chksum(fileobj, mpp_overwr)
2515 end subroutine save_restart
2516 
2517 !---- return true if all fields in fileObj is read only
2518 function all_field_read_only(fileObj)
2519  type(restart_file_type), intent(in) :: fileobj
2520  logical :: all_field_read_only
2521  integer :: j
2522 
2523  all_field_read_only = .true.
2524  do j = 1, fileobj%nvar
2525  if( .not. fileobj%var(j)%read_only) then
2526  all_field_read_only = .false.
2527  exit
2528  endif
2529  enddo
2530 
2531  return
2532 
2533 end function all_field_read_only
2534 
2535 !-------------------------------------------------------------------------------
2536 !
2537 ! saves all registered variables to restart files. Those variables are set
2538 ! through register_restart_field
2539 !
2540 !-------------------------------------------------------------------------------
2541 
2542 subroutine save_compressed_restart(fileObj,restartpath,append,time_level)
2543  type(restart_file_type), intent(inout),target :: fileObj
2544  character(len=336) :: restartpath ! The restart file path (dir/file).
2545 
2546  ! Optional arguments:
2547 
2548  ! If neither append or time_level is present:
2549  ! routine writes both meta data and field data.
2550 
2551  ! If append is present and append=.true.:
2552  ! Only field data is written.
2553  ! The field data is appended to a new time level.
2554  ! time_level must also be present and it must be >= 0.0
2555  ! The value of time_level is written as a new value of the time axis data.
2556 
2557  ! If time_level is present and time_level < 0.0:
2558  ! A new file is opened and only the meta data is written.
2559 
2560  ! If append is present and append=.false.:
2561  ! Behaves the same was as if it were not present. That is, meta data is
2562  ! written and whether or not field data is written is determined by time_level.
2563 
2564  logical, intent(in), optional :: append
2565  real, intent(in), optional :: time_level
2566 
2567  integer :: unit ! The mpp unit of the open file.
2568  type(axistype) :: x_axis, y_axis, z_axis, CC_axis, other_axis
2569  type(axistype) :: t_axis, c_axis, h_axis ! time & sparse compressed vector axes
2570  type(axistype) :: comp_axis
2571  logical :: naxis_z=.false.
2572  type(axistype), dimension(4) :: var_axes
2573  type(var_type), pointer, save :: cur_var=>null()
2574  integer :: i, j, k, l, num_var_axes, cpack, idx, mpp_action
2575  real :: tlev
2576  real, allocatable, dimension(:,:) :: r2d
2577  real, allocatable, dimension(:) :: r1d
2578  real :: r0d
2579  integer(LONG_KIND), allocatable, dimension(:) :: check_val
2580  character(len=256) :: checksum_char
2581  logical :: domain_present, write_meta_data, write_field_data
2582  logical :: c_axis_defined, h_axis_defined, CC_axis_defined
2583  type(domain2d), pointer :: domain =>null()
2584  type(ax_type), pointer :: axis =>null()
2585 
2586  !-- no need to proceed if all the variables are read only.
2587  if( all_field_read_only(fileobj) ) return
2588 
2589  if (.not.ALLOCATED(fileobj%axes(cidx)%idx) .and. .not.ALLOCATED(fileobj%axes(hidx)%idx) ) then
2590  call mpp_error(fatal, "fms_io(save_compressed_restart): A compressed axis has "// &
2591  "not been defined for file "//trim(fileobj%name))
2592  else if (ALLOCATED(fileobj%axes(cidx)%idx)) then
2593  domain =>fileobj%axes(cidx)%domain
2594  else
2595  domain =>fileobj%axes(hidx)%domain
2596  endif
2597 
2598  if(present(append)) then
2599  if(append .and. .not.present(time_level)) then
2600  call mpp_error(fatal, 'fms_io(save_compressed_restart): time_level must be present when append=.true.'// &
2601  ' for file '//trim(fileobj%name))
2602  endif
2603  endif
2604 
2605  mpp_action = mpp_overwr
2606  write_meta_data = .true.
2607  if(present(append)) then
2608  if(append) then
2609  mpp_action = mpp_append
2610  write_meta_data = .false. ! Assuming meta data is already written when routine is called to append to field data.
2611  if(time_level < 0.0) then
2612  call mpp_error(fatal, 'fms_io(save_compressed_restart): time_level cannot be negative when append is .true.'// &
2613  ' for file '//trim(fileobj%name))
2614  endif
2615  endif
2616  endif
2617 
2618  write_field_data = .true.
2619  if(present(time_level)) then
2620  write_field_data = time_level >= 0.0 ! Using negative value of time_level as a flag that there is no valid field data to write.
2621  endif
2622 
2623  call mpp_open(unit,trim(restartpath),action=mpp_action,form=form, &
2624  is_root_pe=fileobj%is_root_pe, domain=domain)
2625 
2626  if(write_meta_data) then
2627  ! User has defined axes and these are assumed to be unique
2628  ! Unfortunately it has proven difficult to write a generalized form because
2629  ! of the variations possible across all of the axes
2630  ! Currently support only 1 user defined axis of each type
2631  ! In fact, this config is specifically designed to support the land model
2632  ! sparse, compressed tile data
2633  axis => fileobj%axes(xidx)
2634  if(.not. ASSOCIATED(axis)) call mpp_error(fatal, "fms_io(save_compressed_restart): "// &
2635  " The X axis has not been defined for "// &
2636  " file "//trim(fileobj%name) )
2637  call mpp_write_meta(unit,x_axis,axis%name,axis%units,axis%longname,data=axis%data,cartesian='X')
2638 
2639  axis => fileobj%axes(yidx)
2640  if(.not. ASSOCIATED(axis)) call mpp_error(fatal, "fms_io(save_compressed_restart): "// &
2641  " The Y axis has not been defined for "// &
2642  " file "//trim(fileobj%name) )
2643  call mpp_write_meta(unit,y_axis,axis%name,axis%units,axis%longname,data=axis%data,cartesian='Y')
2644 
2645  axis => fileobj%axes(zidx)
2646  naxis_z = .false.
2647  if(ASSOCIATED(axis%data))then
2648  call mpp_write_meta(unit,z_axis,axis%name,axis%units,axis%longname, &
2649  data=axis%data,cartesian='Z')
2650  naxis_z = .true.
2651  endif
2652 
2653  axis => fileobj%axes(ccidx)
2654  if(ASSOCIATED(axis%data))then
2655  call mpp_write_meta(unit,cc_axis,axis%name,axis%units,axis%longname,data=axis%data,cartesian='CC')
2656  cc_axis_defined = .true.
2657  else
2658  cc_axis_defined = .false.
2659  endif
2660 
2661  ! The compressed axis
2662  axis => fileobj%axes(cidx)
2663  if(ALLOCATED(axis%idx)) then
2664  call mpp_def_dim(unit,trim(axis%dimlen_name),axis%dimlen,trim(axis%dimlen_lname), (/(i,i=1,axis%dimlen)/))
2665  call mpp_write_meta(unit,c_axis,axis%name,axis%units,axis%longname, &
2666  data=axis%idx,compressed=axis%compressed,min=axis%imin)
2667  c_axis_defined = .true.
2668  else
2669  c_axis_defined = .false.
2670  endif
2671 
2672  axis => fileobj%axes(hidx)
2673  if (ALLOCATED(axis%idx)) then
2674  call mpp_def_dim(unit,trim(axis%dimlen_name),axis%dimlen,trim(axis%dimlen_lname), (/(i,i=1,axis%dimlen)/))
2675  call mpp_write_meta(unit,h_axis,axis%name,axis%units,axis%longname, &
2676  data=axis%idx,compressed=axis%compressed,min=axis%imin)
2677  h_axis_defined = .true.
2678  else
2679  h_axis_defined = .false.
2680  endif
2681 
2682  ! write out time axis
2683  axis => fileobj%axes(tidx)
2684  if(ASSOCIATED(axis%data))then
2685  call mpp_write_meta(unit,t_axis, axis%name, units=axis%units, longname=axis%longname, cartesian='T', calendar=axis%calendar)
2686  else
2687  call mpp_write_meta(unit,t_axis, 'Time','time level','Time',cartesian='T')
2688  endif
2689 
2690  ! write metadata for fields
2691  do j = 1,fileobj%nvar
2692  cur_var => fileobj%var(j)
2693  if(cur_var%read_only) cycle
2694  if(cur_var%siz(4) > 1 .AND. cur_var%siz(4) .NE. fileobj%max_ntime ) call mpp_error(fatal, &
2695  "fms_io(save_restart): "//trim(cur_var%name)//" in file "//trim(fileobj%name)// &
2696  " has more than one time level, but number of time level is not equal to max_ntime")
2697 
2698  select case (trim(cur_var%compressed_axis))
2699  case ('C')
2700  comp_axis = c_axis
2701  other_axis = z_axis
2702  case ('C_CC')
2703  comp_axis = c_axis
2704  other_axis = cc_axis
2705  case ('H')
2706  comp_axis = h_axis
2707  case default
2708  if (ALLOCATED(fileobj%axes(cidx)%idx)) then
2709  comp_axis = c_axis
2710  other_axis = z_axis
2711  else
2712  comp_axis = h_axis
2713  endif
2714  end select
2715 
2716  if(cur_var%ndim == 0) then
2717  num_var_axes = 1
2718  var_axes(1) = t_axis
2719  elseif(cur_var%ndim == 1) then
2720  num_var_axes = 1
2721  var_axes(1) = comp_axis
2722  if(cur_var%siz(4) == fileobj%max_ntime) then
2723  num_var_axes = 2
2724  var_axes(2) = t_axis
2725  endif
2726  elseif(cur_var%ndim == 2) then
2727  num_var_axes = 2
2728  var_axes(1) = comp_axis
2729  var_axes(2) = other_axis
2730  if(cur_var%siz(4) == fileobj%max_ntime) then
2731  num_var_axes = 3
2732  var_axes(3) = t_axis
2733  endif
2734  elseif(cur_var%ndim == 3) then
2735  num_var_axes = 3
2736  var_axes(1) = comp_axis
2737  var_axes(2) = z_axis
2738  var_axes(3) = cc_axis
2739  if(cur_var%siz(4) == fileobj%max_ntime) then
2740  num_var_axes = 4
2741  var_axes(4) = t_axis
2742  endif
2743  else
2744  call mpp_error(fatal, "fms_io(save_compressed_restart): "//trim(cur_var%name)//" in file "// &
2745  trim(fileobj%name)//" has more than three dimensions (not including time level)")
2746  endif
2747 
2748  cpack = pack_size ! Default size of real
2749  allocate(check_val(max(1,cur_var%siz(4))))
2750  do k = 1, cur_var%siz(4)
2751  if ( Associated(fileobj%p0dr(k,j)%p) ) then
2752  check_val(k) = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/), mask_val=cur_var%default_data)
2753  else if ( Associated(fileobj%p1dr(k,j)%p) ) then
2754  check_val(k) = mpp_chksum(fileobj%p1dr(k,j)%p(:), mask_val=cur_var%default_data)
2755  else if ( Associated(fileobj%p2dr(k,j)%p) ) then
2756  check_val(k) = mpp_chksum(fileobj%p2dr(k,j)%p(:,:), mask_val=cur_var%default_data)
2757  else if ( Associated(fileobj%p3dr(k,j)%p) ) then
2758  check_val(k) = mpp_chksum(fileobj%p3dr(k,j)%p(:,:,:))
2759  else if ( Associated(fileobj%p0di(k,j)%p) ) then
2760  check_val(k) = fileobj%p0di(k,j)%p
2761  cpack = 0 ! Write data as integer*4
2762  else if ( Associated(fileobj%p1di(k,j)%p) ) then
2763  check_val(k) = mpp_chksum(fileobj%p1di(k,j)%p(:), mask_val=cur_var%default_data)
2764  cpack = 0 ! Write data as integer*4
2765  else if ( Associated(fileobj%p2di(k,j)%p) ) then
2766  check_val(k) = mpp_chksum(fileobj%p2di(k,j)%p(:,:), mask_val=cur_var%default_data)
2767  cpack = 0 ! Write data as integer*4
2768  else if ( Associated(fileobj%p3di(k,j)%p) ) then
2769  call mpp_error(fatal, "fms_io(save_compressed_restart): integer 3D restart fields are not currently supported"// &
2770  trim(cur_var%name)//" of file "//trim(fileobj%name) )
2771  else
2772  call mpp_error(fatal, "fms_io(save_restart): There is no pointer associated with the data of field "// &
2773  trim(cur_var%name)//" of file "//trim(fileobj%name) )
2774  end if
2775  enddo
2776 ! The chksum could not reproduce when running on different processor count. So commenting out now.
2777 ! Also the chksum of compressed data is not read.
2778  if(write_field_data) then ! Write checksums only if valid field data exists
2779  call mpp_write_meta(unit,cur_var%field, var_axes(1:num_var_axes), cur_var%name, &
2780  cur_var%units,cur_var%longname,pack=cpack,checksum=check_val,fill=cur_var%default_data)
2781  else
2782  call mpp_write_meta(unit,cur_var%field, var_axes(1:num_var_axes), cur_var%name, &
2783  cur_var%units,cur_var%longname,pack=cpack,fill=cur_var%default_data)
2784  endif
2785  deallocate(check_val)
2786  enddo
2787 
2788  ! write values for ndim of spatial and compressed axes
2789  call mpp_write(unit,x_axis)
2790  call mpp_write(unit,y_axis)
2791  if (c_axis_defined) call mpp_write(unit,c_axis)
2792  if (h_axis_defined) call mpp_write(unit,h_axis)
2793  if (cc_axis_defined) call mpp_write(unit,cc_axis)
2794  if(naxis_z) call mpp_write(unit,z_axis)
2795 
2796  endif ! End of section to write meta data. Write meta data only if not appending.
2797 
2798  if(write_field_data) then
2799  ! write data of each field
2800  do k = 1, fileobj%max_ntime
2801  if(present(time_level)) then
2802  tlev = time_level
2803  else
2804  tlev = k
2805  endif
2806  do j=1,fileobj%nvar
2807  cur_var => fileobj%var(j)
2808  if(cur_var%read_only) cycle
2809 
2810  select case (trim(cur_var%compressed_axis))
2811  case ('C')
2812  idx = cidx
2813  case ('H')
2814  idx = hidx
2815  case default
2816  if (ALLOCATED(fileobj%axes(cidx)%idx)) then
2817  idx = cidx
2818  else
2819  idx = hidx
2820  endif
2821  end select
2822 
2823  ! If some fields only have one time level, we do not need to write the second level, just keep
2824  ! the data missing.
2825  if(k <= cur_var%siz(4)) then
2826  if ( Associated(fileobj%p0dr(k,j)%p) ) then
2827  call mpp_write(unit, cur_var%field, fileobj%p0dr(k,j)%p, tlev)
2828  elseif ( Associated(fileobj%p1dr(k,j)%p) ) then
2829  call mpp_write_compressed(unit, cur_var%field, domain, fileobj%p1dr(k,j)%p, &
2830  fileobj%axes(idx)%nelems(:), tstamp=tlev, default_data=cur_var%default_data)
2831  elseif ( Associated(fileobj%p2dr(k,j)%p) ) then
2832  call mpp_write_compressed(unit, cur_var%field, domain, fileobj%p2dr(k,j)%p, &
2833  fileobj%axes(idx)%nelems(:), tstamp=tlev, default_data=cur_var%default_data)
2834  elseif ( Associated(fileobj%p3dr(k,j)%p) ) then
2835  call mpp_write_compressed(unit, cur_var%field, domain, fileobj%p3dr(k,j)%p, &
2836  fileobj%axes(idx)%nelems(:), tstamp=tlev, default_data=cur_var%default_data)
2837  elseif ( Associated(fileobj%p0di(k,j)%p) ) then
2838  r0d = fileobj%p0di(k,j)%p
2839  call mpp_write(unit, cur_var%field, r0d, tlev)
2840  elseif ( Associated(fileobj%p1di(k,j)%p) ) then
2841  allocate(r1d(cur_var%siz(1)) )
2842  r1d = fileobj%p1di(k,j)%p
2843  call mpp_write_compressed(unit, cur_var%field, domain, r1d, &
2844  fileobj%axes(idx)%nelems(:), tstamp=tlev, default_data=cur_var%default_data)
2845  deallocate(r1d)
2846  elseif ( Associated(fileobj%p2di(k,j)%p) ) then
2847  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
2848  r2d = fileobj%p2di(k,j)%p
2849  call mpp_write_compressed(unit, cur_var%field, domain, r2d, &
2850  fileobj%axes(idx)%nelems(:), tstamp=tlev, default_data=cur_var%default_data)
2851  deallocate(r2d)
2852  else
2853  call mpp_error(fatal, "fms_io(save_restart): There is no pointer associated with the data of field "// &
2854  trim(cur_var%name)//" of file "//trim(fileobj%name) )
2855  endif
2856  endif
2857  enddo ! end j loop
2858  enddo ! end k loop
2859  cur_var =>null()
2860  endif
2861  call mpp_close(unit)
2862 end subroutine save_compressed_restart
2863 
2864 !-------------------------------------------------------------------------------
2865 !
2866 ! saves all registered variables to restart files. Those variables are set
2867 ! through register_restart_field
2868 !
2869 !-------------------------------------------------------------------------------
2870 
2871 subroutine save_unlimited_axis_restart(fileObj,restartpath)
2872  type(restart_file_type), intent(inout),target :: fileObj
2873  character(len=336) :: restartpath ! The restart file path (dir/file).
2874 
2875  integer :: unit ! The mpp unit of the open file.
2876  type(axistype) :: u_axis
2877  type(axistype), dimension(4) :: var_axes
2878  type(var_type), pointer, save :: cur_var=>null()
2879  integer :: i, j, k, l, num_var_axes, cpack, idx
2880  real, allocatable, dimension(:) :: r1d
2881  integer(LONG_KIND) :: check_val
2882  character(len=256) :: checksum_char
2883  type(domain2d), pointer :: domain =>null()
2884  type(ax_type), pointer :: axis =>null()
2885 
2886 
2887  if ( .NOT.fileobj%unlimited_axis ) then
2888  call mpp_error(fatal, "fms_io(save_unlimited_axis_restart): An unlimited axis has "// &
2889  "not been defined for file "//trim(fileobj%name))
2890  endif
2891  domain =>fileobj%axes(uidx)%domain
2892 
2893  call mpp_open(unit,trim(restartpath),action=mpp_overwr,form=form, &
2894  is_root_pe=fileobj%is_root_pe, domain=domain)
2895 
2896  ! Set unlimited axis
2897  axis => fileobj%axes(uidx)
2898  call mpp_write_meta(unit,u_axis,axis%name,data=sum(axis%nelems(:)),unlimited=.true.)
2899  call write_meta_global(unit,fileobj) ! Write any additional global metadata
2900  call mpp_write(unit,u_axis)
2901 
2902  ! write metadata for fields
2903  do j = 1,fileobj%nvar
2904  cur_var => fileobj%var(j)
2905  if(cur_var%siz(4) > 1) call mpp_error(fatal, &
2906  "fms_io(save_restart): "//trim(cur_var%name)//" in file "//trim(fileobj%name)// &
2907  " has more than one time level. Only single time level is currrently supported")
2908 
2909  if(cur_var%ndim == 1) then
2910  num_var_axes = 1
2911  var_axes(1) = u_axis
2912  else
2913  call mpp_error(fatal, 'fms_io(save_unlimited_axis_restart): Only vectors are currently supported')
2914  endif
2915 
2916  cpack = pack_size ! Default size of real
2917  if ( Associated(fileobj%p1dr(1,j)%p) ) then
2918  check_val = mpp_chksum(fileobj%p1dr(1,j)%p(:))
2919  else if ( Associated(fileobj%p1di(1,j)%p) ) then
2920  ! Fill values are -HUGE(i4) which don't behave as desired for checksum algorithm
2921  check_val = mpp_chksum(int(fileobj%p1di(1,j)%p(:),8))
2922  cpack = 0 ! Write data as integer*4
2923  else
2924  call mpp_error(fatal, "fms_io(save_unlimited_axis_restart): There is no pointer associated with the record data of field "// &
2925  trim(cur_var%name)//" of file "//trim(fileobj%name) )
2926  end if
2927  call mpp_write_meta(unit,cur_var%field, var_axes(1:num_var_axes), cur_var%name, &
2928  cur_var%units,cur_var%longname,pack=cpack,checksum=(/check_val/))
2929  enddo ! end j loop
2930 
2931  ! write data of each field
2932  do j=1,fileobj%nvar
2933  cur_var => fileobj%var(j)
2934  if ( Associated(fileobj%p1dr(1,j)%p) ) then
2935  call mpp_write_unlimited_axis(unit,cur_var%field,domain,fileobj%p1dr(1,j)%p,fileobj%axes(uidx)%nelems(:))
2936  elseif ( Associated(fileobj%p1di(1,j)%p) ) then
2937  allocate(r1d(cur_var%siz(1)) )
2938  r1d = fileobj%p1di(1,j)%p
2939  call mpp_write_unlimited_axis(unit,cur_var%field,domain,r1d,fileobj%axes(uidx)%nelems(:))
2940  deallocate(r1d)
2941  else
2942  call mpp_error(fatal, "fms_io(save_restart): There is no pointer associated with the data of field "// &
2943  trim(cur_var%name)//" of file "//trim(fileobj%name) )
2944  endif
2945  enddo ! end j loop
2946  call mpp_close(unit)
2947  cur_var =>null()
2948 end subroutine save_unlimited_axis_restart
2949 
2950 !-------------------------------------------------------------------------------
2951 !
2952 ! saves all registered variables to restart files. Those variables are set
2953 ! through register_restart_field
2954 !
2955 !-------------------------------------------------------------------------------
2956 
2957 subroutine save_default_restart(fileObj,restartpath)
2958  type(restart_file_type), intent(inout) :: fileObj
2959  character(len=336) :: restartpath ! The restart file path (dir/file).
2960 
2961  character(len=8) :: suffix ! A suffix (like _2) that is appended to the name of files after the first.
2962  integer :: var_sz, size_in_file ! The size in bytes of each variable and of the variables already in a file.
2963  integer :: unit ! The mpp unit of the open file.
2964  real, dimension(max_axis_size) :: axisdata
2965  integer, dimension(max_axes) :: id_x_axes, siz_x_axes
2966  integer, dimension(max_axes) :: id_y_axes, siz_y_axes
2967  integer, dimension(max_axes) :: id_z_axes, siz_z_axes
2968  integer, dimension(max_axes) :: id_a_axes, siz_a_axes
2969  integer, dimension(max_axes) :: x_axes_indx, y_axes_indx, z_axes_indx, a_axes_indx
2970  type(axistype), dimension(max_axes) :: x_axes, y_axes, z_axes, a_axes
2971  type(axistype) :: t_axes
2972  integer :: num_var_axes
2973  type(axistype), dimension(5) :: var_axes
2974  type(var_type), pointer, save :: cur_var=>null()
2975  integer :: num_x_axes, num_y_axes, num_z_axes, num_a_axes
2976  integer :: naxes_x, naxes_y, naxes_z, naxes_a
2977  integer :: i, j, k, l, siz, ind_dom
2978  logical :: domain_present
2979  real :: tlev
2980  real(DOUBLE_KIND) :: tlev_r8
2981  character(len=10) :: axisname
2982  integer :: meta_size
2983  type(domain2d) :: domain
2984 
2985  real, allocatable, dimension(:,:,:) :: r3d
2986  real, allocatable, dimension(:,:) :: r2d
2987  real, allocatable, dimension(:) :: r1d
2988  real :: r0d
2989  integer(LONG_KIND), allocatable, dimension(:) :: check_val
2990  character(len=256) :: checksum_char
2991  integer :: isc, iec, jsc, jec
2992  integer :: isg, ieg, jsg, jeg
2993  integer :: ishift, jshift, iadd, jadd, cpack_size
2994  logical :: write_on_this_pe
2995  type(domain2d), pointer :: io_domain =>null()
2996 
2997  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(save_restart): " // &
2998  "restart_file_type data must be initialized by calling register_restart_field before using it")
2999 
3000  !-- no need to proceed if all the variables are read only.
3001  if( all_field_read_only(fileobj) ) return
3002 
3003  do i=1,max_axis_size
3004  axisdata(i) = i
3005  enddo
3006 
3007  !--- check if any field in this file present domain.
3008  domain_present = .false.
3009  do j = 1, fileobj%nvar
3010  if (fileobj%var(j)%domain_present) then
3011  domain_present = .true.
3012  ind_dom = j
3013  exit
3014  end if
3015  end do
3016  num_x_axes = unique_axes(fileobj, 1, id_x_axes, siz_x_axes, domain_x)
3017  num_y_axes = unique_axes(fileobj, 2, id_y_axes, siz_y_axes, domain_y)
3018  num_z_axes = unique_axes(fileobj, 3, id_z_axes, siz_z_axes )
3019  num_a_axes = unique_axes(fileobj, 4, id_a_axes, siz_a_axes )
3020 
3021  write_on_this_pe = .false.
3022  if(domain_present) then
3023  io_domain => mpp_get_io_domain(array_domain(fileobj%var(ind_dom)%domain_idx))
3024  if(associated(io_domain)) then
3025  if(mpp_domain_is_tile_root_pe(io_domain)) write_on_this_pe = .true.
3026  endif
3027  endif
3028  !--- always write out from root pe
3029  if( fileobj%is_root_pe ) write_on_this_pe = .true.
3030 
3031  if( domain_present ) then
3032  call mpp_open(unit,trim(restartpath),action=mpp_overwr,form=form,&
3033  is_root_pe=fileobj%is_root_pe, domain=array_domain(fileobj%var(ind_dom)%domain_idx) )
3034  else ! global data
3035  call mpp_open(unit,trim(restartpath),action=mpp_overwr,form=form,threading=mpp_single,&
3036  fileset=mpp_single, is_root_pe=fileobj%is_root_pe)
3037  end if
3038 
3039  naxes_x = 0
3040  x_axes_indx = 0
3041  y_axes_indx = 0
3042  z_axes_indx = 0
3043  a_axes_indx = 0
3044 
3045  ! write_out x_axes
3046  do j = 1, num_x_axes
3047  ! make sure this axis is used by some variable
3048  do l=1,fileobj%nvar
3049  if(fileobj%var(l)%read_only) cycle
3050  if( fileobj%var(l)%id_axes(1) == j ) exit
3051  end do
3052  if( l > fileobj%nvar ) cycle
3053  naxes_x = naxes_x + 1
3054  x_axes_indx(naxes_x) = j
3055  if (naxes_x < 10) then
3056  write(axisname,'(a,i1)') 'xaxis_',naxes_x
3057  else
3058  write(axisname,'(a,i2)') 'xaxis_',naxes_x
3059  endif
3060  if(id_x_axes(j) > 0) then
3061  call mpp_write_meta(unit,x_axes(j),axisname,'none',axisname, &
3062  data=axisdata(1:siz_x_axes(j)),domain=domain_x(id_x_axes(j)),cartesian='X')
3063  else
3064  call mpp_write_meta(unit,x_axes(j),axisname,'none',axisname, &
3065  data=axisdata(1:siz_x_axes(j)),cartesian='X')
3066  endif
3067  end do
3068 
3069  ! write out y_axes
3070  naxes_y = 0
3071  do j = 1, num_y_axes
3072  ! make sure this axis is used by some variable
3073  do l=1,fileobj%nvar
3074  if(fileobj%var(l)%read_only) cycle
3075  if( fileobj%var(l)%id_axes(2) == j ) exit
3076  end do
3077  if( l > fileobj%nvar ) cycle
3078  naxes_y = naxes_y + 1
3079  y_axes_indx(naxes_y) = j
3080  if (naxes_y < 10) then
3081  write(axisname,'(a,i1)') 'yaxis_',naxes_y
3082  else
3083  write(axisname,'(a,i2)') 'yaxis_',naxes_y
3084  endif
3085  if(id_y_axes(j) > 0) then
3086  call mpp_write_meta(unit,y_axes(j),axisname,'none',axisname, &
3087  data=axisdata(1:siz_y_axes(j)),domain=domain_y(id_y_axes(j)),cartesian='Y')
3088  else
3089  call mpp_write_meta(unit,y_axes(j),axisname,'none',axisname, &
3090  data=axisdata(1:siz_y_axes(j)),cartesian='Y')
3091  endif
3092  end do
3093 
3094  ! write out z_axes
3095  naxes_z = 0
3096  do j = 1, num_z_axes
3097  ! make sure this axis is used by some variable
3098  do l=1,fileobj%nvar
3099  if(fileobj%var(l)%read_only) cycle
3100  if( fileobj%var(l)%id_axes(3) == j ) exit
3101  end do
3102  if( l > fileobj%nvar ) cycle
3103  naxes_z = naxes_z + 1
3104  z_axes_indx(naxes_z) = j
3105  if (naxes_z < 10) then
3106  write(axisname,'(a,i1)') 'zaxis_',naxes_z
3107  else
3108  write(axisname,'(a,i2)') 'zaxis_',naxes_z
3109  endif
3110  call mpp_write_meta(unit,z_axes(j),axisname,'none',axisname, &
3111  data=axisdata(1:siz_z_axes(j)),cartesian='Z')
3112  end do
3113 
3114  ! write out a_axes
3115  naxes_a = 0
3116  do j = 1, num_a_axes
3117  ! make sure this axis is used by some variable
3118  do l=1,fileobj%nvar
3119  if(fileobj%var(l)%read_only) cycle
3120  if( fileobj%var(l)%id_axes(4) == j ) exit
3121  end do
3122  if( l > fileobj%nvar ) cycle
3123  naxes_a = naxes_a + 1
3124  a_axes_indx(naxes_a) = j
3125  if (naxes_a < 10) then
3126  write(axisname,'(a,i1)') 'aaxis_',naxes_a
3127  else
3128  write(axisname,'(a,i2)') 'aaxis_',naxes_a
3129  endif
3130  call mpp_write_meta(unit,a_axes(j),axisname,'none',axisname, &
3131  data=axisdata(1:siz_a_axes(j)),cartesian='N')
3132  end do
3133 
3134  ! write out time axis
3135  call mpp_write_meta(unit,t_axes,&
3136  'Time','time level','Time',cartesian='T')
3137  ! write metadata for fields
3138  do j = 1,fileobj%nvar
3139  cur_var => fileobj%var(j)
3140  if(cur_var%read_only) cycle
3141  if(cur_var%siz(4) > 1 .AND. cur_var%siz(4) .NE. fileobj%max_ntime ) call mpp_error(fatal, &
3142  "fms_io(save_restart): "//trim(cur_var%name)//" in file "//trim(fileobj%name)// &
3143  " has more than one time level, but number of time level is not equal to max_ntime")
3144 
3145  if(cur_var%ndim == 0) then
3146  num_var_axes = 1
3147  var_axes(1) = t_axes
3148  else if(cur_var%ndim == 1) then
3149  num_var_axes = 1
3150  var_axes(1) = x_axes(cur_var%id_axes(1))
3151  if(cur_var%siz(4) == fileobj%max_ntime) then
3152  num_var_axes = 2
3153  var_axes(2) = t_axes
3154  end if
3155  else if(cur_var%ndim == 2) then
3156  num_var_axes = 2
3157  var_axes(1) = x_axes(cur_var%id_axes(1))
3158  var_axes(2) = y_axes(cur_var%id_axes(2))
3159  if(cur_var%siz(4) == fileobj%max_ntime) then
3160  num_var_axes = 3
3161  var_axes(3) = t_axes
3162  end if
3163  else if(cur_var%ndim == 3) then
3164  num_var_axes = 3
3165  var_axes(1) = x_axes(cur_var%id_axes(1))
3166  var_axes(2) = y_axes(cur_var%id_axes(2))
3167  var_axes(3) = z_axes(cur_var%id_axes(3))
3168  if(cur_var%siz(4) == fileobj%max_ntime) then
3169  num_var_axes = 4
3170  var_axes(4) = t_axes
3171  end if
3172  else if(cur_var%ndim == 4) then
3173  num_var_axes = 4
3174  var_axes(1) = x_axes(cur_var%id_axes(1))
3175  var_axes(2) = y_axes(cur_var%id_axes(2))
3176  var_axes(3) = z_axes(cur_var%id_axes(3))
3177  var_axes(4) = a_axes(cur_var%id_axes(4))
3178  if(cur_var%siz(4) == fileobj%max_ntime) then
3179  num_var_axes = 5
3180  var_axes(5) = t_axes
3181  end if
3182  end if
3183 
3184  if ( cur_var%domain_idx > 0) then
3185  call mpp_get_compute_domain(array_domain(cur_var%domain_idx), isc, iec, jsc, jec)
3186  call mpp_get_global_domain(array_domain(cur_var%domain_idx), isg, ieg, jsg, jeg)
3187  call mpp_get_domain_shift(array_domain(cur_var%domain_idx), ishift, jshift, cur_var%position)
3188  else if (ASSOCIATED(current_domain)) then
3189  call mpp_get_compute_domain(current_domain, isc, iec, jsc, jec)
3190  call mpp_get_global_domain(current_domain, isg, ieg, jsg, jeg)
3191  call mpp_get_domain_shift(current_domain, ishift, jshift, cur_var%position)
3192  else
3193  iec = cur_var%ie
3194  isc = cur_var%is
3195  ieg = cur_var%ie
3196  jec = cur_var%je
3197  jsc = cur_var%js
3198  jeg = cur_var%je
3199  ishift = 0
3200  jshift = 0
3201  endif
3202 ! call return_domain(domain)
3203  iadd = iec-isc ! Size of the i-dimension on this processor (-1 as it is an increment)
3204  jadd = jec-jsc ! Size of the j-dimension on this processor
3205  if(iec == ieg) iadd = iadd + ishift
3206  if(jec == jeg) jadd = jadd + jshift
3207 
3208  allocate(check_val(max(1,cur_var%siz(4))))
3209  cpack_size = pack_size
3210  do k = 1, cur_var%siz(4)
3211  if ( Associated(fileobj%p0dr(k,j)%p) ) then
3212  check_val(k) = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/) )
3213  else if ( Associated(fileobj%p1dr(k,j)%p) ) then
3214  check_val(k) = mpp_chksum(fileobj%p1dr(k,j)%p, (/mpp_pe()/) )
3215  else if ( Associated(fileobj%p2dr(k,j)%p) ) then
3216  check_val(k) = mpp_chksum(fileobj%p2dr(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd) )
3217  else if ( Associated(fileobj%p3dr(k,j)%p) ) then
3218  check_val(k) = mpp_chksum(fileobj%p3dr(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd, :) )
3219  else if ( Associated(fileobj%p2dr8(k,j)%p) ) then
3220  cpack_size = 1
3221  check_val(k) = mpp_chksum(fileobj%p2dr8(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd) )
3222  else if ( Associated(fileobj%p3dr8(k,j)%p) ) then
3223  cpack_size = 1
3224  check_val(k) = mpp_chksum(fileobj%p3dr8(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd, :) )
3225  else if ( Associated(fileobj%p4dr(k,j)%p) ) then
3226  check_val(k) = mpp_chksum(fileobj%p4dr(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd, :, :) )
3227  else if ( Associated(fileobj%p0di(k,j)%p) ) then
3228  check_val(k) = fileobj%p0di(k,j)%p
3229  else if ( Associated(fileobj%p1di(k,j)%p) ) then
3230  check_val(k) = mpp_chksum(fileobj%p1di(k,j)%p, (/mpp_pe()/) )
3231  else if ( Associated(fileobj%p2di(k,j)%p) ) then
3232  check_val(k) = mpp_chksum(fileobj%p2di(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd) )
3233  else if ( Associated(fileobj%p3di(k,j)%p) ) then
3234  check_val(k) = mpp_chksum(fileobj%p3di(k,j)%p(cur_var%is:cur_var%is+iadd, cur_var%js:cur_var%js+jadd, :))
3235  else
3236  call mpp_error(fatal, "fms_io(save_restart): There is no pointer associated with the data of field "// &
3237  trim(cur_var%name)//" of file "//trim(fileobj%name) )
3238  end if
3239  enddo
3240  call mpp_write_meta(unit,cur_var%field, var_axes(1:num_var_axes), cur_var%name, &
3241  cur_var%units,cur_var%longname,pack=cpack_size,checksum=check_val)
3242  deallocate(check_val)
3243  enddo
3244 
3245  ! write values for ndim of spatial axes
3246  do j = 1, naxes_x
3247  call mpp_write(unit,x_axes(x_axes_indx(j)))
3248  enddo
3249  do j = 1, naxes_y
3250  call mpp_write(unit,y_axes(y_axes_indx(j)))
3251  enddo
3252  do j = 1, naxes_z
3253  call mpp_write(unit,z_axes(z_axes_indx(j)))
3254  enddo
3255 
3256  do j = 1, naxes_a
3257  call mpp_write(unit,a_axes(a_axes_indx(j)))
3258  enddo
3259 
3260  ! write data of each field
3261  do k = 1, fileobj%max_ntime
3262  do j=1,fileobj%nvar
3263  cur_var => fileobj%var(j)
3264  if(cur_var%read_only) cycle
3265  tlev =k
3266  tlev_r8=k
3267  ! If some fields only have one time level, we do not need to write the second level, just keep
3268  ! the data missing.
3269  if(k <= cur_var%siz(4)) then
3270  if(cur_var%domain_present) then ! one 2-D or 3-D case possible present domain
3271  if( Associated(fileobj%p2dr(k,j)%p) ) then
3272  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), fileobj%p2dr(k,j)%p, tlev, &
3273  default_data=cur_var%default_data)
3274  else if( Associated(fileobj%p3dr(k,j)%p) ) then
3275  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), fileobj%p3dr(k,j)%p, tlev, &
3276  default_data=cur_var%default_data)
3277  else if( Associated(fileobj%p2dr8(k,j)%p) ) then
3278  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), fileobj%p2dr8(k,j)%p, tlev_r8, &
3279  default_data=real(cur_var%default_data,kind=double_kind))
3280  else if( Associated(fileobj%p3dr8(k,j)%p) ) then
3281  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), fileobj%p3dr8(k,j)%p, tlev_r8, &
3282  default_data=real(cur_var%default_data,kind=double_kind))
3283  else if( Associated(fileobj%p4dr(k,j)%p) ) then
3284  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), fileobj%p4dr(k,j)%p, tlev, &
3285  default_data=cur_var%default_data)
3286  else if( Associated(fileobj%p2di(k,j)%p) ) then
3287  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
3288  r2d = fileobj%p2di(k,j)%p
3289  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), r2d, tlev, &
3290  default_data=cur_var%default_data)
3291  deallocate(r2d)
3292  else if( Associated(fileobj%p3di(k,j)%p) ) then
3293  allocate(r3d(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3)) )
3294  r3d = fileobj%p3di(k,j)%p
3295  call mpp_write(unit, cur_var%field, array_domain(cur_var%domain_idx), r3d, tlev, &
3296  default_data=cur_var%default_data)
3297  deallocate(r3d)
3298  else
3299  call mpp_error(fatal, "fms_io(save_restart): domain is present, "// &
3300  "field "//trim(cur_var%name)//" of file "//trim(fileobj%name)// &
3301  ", but none of p2dr, p3dr, p2di and p3di is associated")
3302  end if
3303  else if (write_on_this_pe) then
3304  if ( Associated(fileobj%p0dr(k,j)%p) ) then
3305  call mpp_write(unit, cur_var%field, fileobj%p0dr(k,j)%p, tlev)
3306  else if ( Associated(fileobj%p1dr(k,j)%p) ) then
3307  call mpp_write(unit, cur_var%field, fileobj%p1dr(k,j)%p, tlev)
3308  else if ( Associated(fileobj%p2dr(k,j)%p) ) then
3309  call mpp_write(unit, cur_var%field, fileobj%p2dr(k,j)%p, tlev)
3310  else if ( Associated(fileobj%p3dr(k,j)%p) ) then
3311  call mpp_write(unit, cur_var%field, fileobj%p3dr(k,j)%p, tlev)
3312 ! else if ( Associated(fileObj%p2dr8(k,j)%p) ) then
3313 ! call mpp_write(unit, cur_var%field, fileObj%p2dr8(k,j)%p, tlev_r8)
3314 ! else if ( Associated(fileObj%p3dr8(k,j)%p) ) then
3315 ! call mpp_write(unit, cur_var%field, fileObj%p3dr8(k,j)%p, tlev_r8)
3316  else if ( Associated(fileobj%p4dr(k,j)%p) ) then
3317  call mpp_write(unit, cur_var%field, fileobj%p4dr(k,j)%p, tlev)
3318  else if ( Associated(fileobj%p0di(k,j)%p) ) then
3319  r0d = fileobj%p0di(k,j)%p
3320  call mpp_write(unit, cur_var%field, r0d, tlev)
3321  else if ( Associated(fileobj%p1di(k,j)%p) ) then
3322  allocate(r1d(cur_var%siz(1)) )
3323  r1d = fileobj%p1di(k,j)%p
3324  call mpp_write(unit, cur_var%field, r1d, tlev)
3325  deallocate(r1d)
3326  else if ( Associated(fileobj%p2di(k,j)%p) ) then
3327  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
3328  r2d = fileobj%p2di(k,j)%p
3329  call mpp_write(unit, cur_var%field, r2d, tlev)
3330  deallocate(r2d)
3331  else if ( Associated(fileobj%p3di(k,j)%p) ) then
3332  allocate(r3d(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3)) )
3333  r3d = fileobj%p3di(k,j)%p
3334  call mpp_write(unit, cur_var%field, r3d, tlev)
3335  deallocate(r3d)
3336  else
3337  call mpp_error(fatal, "fms_io(save_restart): There is no pointer associated with the data of field "// &
3338  trim(cur_var%name)//" of file "//trim(fileobj%name) )
3339  end if
3340  end if
3341  end if
3342  enddo ! end j loop
3343  enddo ! end k loop
3344  call mpp_close(unit)
3345  cur_var =>null()
3346 end subroutine save_default_restart
3347 !-------------------------------------------------------------------------------
3348 !
3349 ! saves all registered border/halo variables to restart files. Those variables
3350 ! are set through register_restart_field (region option)
3351 !
3352 !-------------------------------------------------------------------------------
3353 subroutine save_restart_border (fileObj, time_stamp, directory)
3354  type(restart_file_type), intent(inout) :: fileobj
3355  character(len=*), intent(in), optional :: directory
3356  character(len=*), intent(in), optional :: time_stamp
3357 
3358  character(len=256) :: dir
3359  character(len=256) :: restartpath ! The restart file path (dir/file).
3360  character(len=80) :: restartname ! The restart file name (no dir).
3361 !rab integer :: start_var, next_var ! The starting variables of the current and next files.
3362  integer :: unit ! The mpp unit of the open file.
3363  real, dimension(max_axis_size) :: axisdata
3364  integer, dimension(max_axes) :: id_x_axes, siz_x_axes
3365  integer, dimension(max_axes) :: id_y_axes, siz_y_axes
3366  integer, dimension(max_axes) :: id_z_axes, siz_z_axes
3367  integer, dimension(max_axes) :: x_axes_indx, y_axes_indx, z_axes_indx
3368  type(axistype), dimension(max_axes) :: x_axes, y_axes, z_axes
3369  type(axistype) :: t_axes
3370  integer :: num_var_axes
3371  type(axistype), dimension(4) :: var_axes
3372  type(var_type), pointer, save :: cur_var=>null()
3373  integer :: num_x_axes, num_y_axes, num_z_axes
3374  integer :: naxes_x, naxes_y, naxes_z
3375  integer :: i, j, k, l
3376  integer :: isc, iec, jsc, jec
3377  integer :: is, ie, js, je
3378  integer :: i_add, i1, i2
3379  integer :: j_add, j1, j2
3380  integer :: i_glob, j_glob, k_glob
3381  real :: tlev
3382  character(len=10) :: axisname
3383 
3384  real, allocatable, dimension(:,:) :: r2d
3385  real, allocatable, dimension(:,:,:) :: r3d
3386  integer(LONG_KIND), allocatable, dimension(:) :: check_val
3387 
3388  !-- no need to proceed if all the variables are read only.
3389  if( all_field_read_only(fileobj) ) return
3390 
3391  do i=1,max_axis_size
3392  axisdata(i) = i
3393  enddo
3394 
3395  dir = "RESTART"
3396  if(present(directory)) dir = directory
3397 
3398  restartname = fileobj%name
3399  if (time_stamp_restart) then
3400  if (PRESENT(time_stamp)) then
3401  restartname = trim(time_stamp)//"."//trim(restartname)
3402  endif
3403  end if
3404  if (len_trim(dir) > 0) then
3405  restartpath = trim(dir)//"/"// trim(restartname)
3406  else
3407  restartpath = trim(restartname)
3408  end if
3409 
3410  num_x_axes = unique_axes(fileobj, 1, id_x_axes, siz_x_axes)
3411  num_y_axes = unique_axes(fileobj, 2, id_y_axes, siz_y_axes)
3412  num_z_axes = unique_axes(fileobj, 3, id_z_axes, siz_z_axes)
3413 
3414  call mpp_open(unit,trim(restartpath),action=mpp_overwr,form=mpp_netcdf,threading=mpp_single,&
3415  fileset=mpp_single, is_root_pe=fileobj%is_root_pe)
3416 
3417 ! write out axes
3418  naxes_x = 0
3419  x_axes_indx = 0
3420  y_axes_indx = 0
3421  z_axes_indx = 0
3422 
3423 ! write out x_axes metadata
3424  do j = 1, num_x_axes
3425  ! make sure this axis is used by some variable
3426  do l=1, fileobj%nvar
3427  if(fileobj%var(l)%read_only) cycle
3428  if (fileobj%var(l)%id_axes(1) == j) exit
3429  end do
3430  if( l > fileobj%nvar ) cycle
3431  naxes_x = naxes_x + 1
3432  x_axes_indx(naxes_x) = j
3433  if (naxes_x < 10) then
3434  write(axisname,'(a,i1)') 'xaxis_',naxes_x
3435  else
3436  write(axisname,'(a,i2)') 'xaxis_',naxes_x
3437  endif
3438  call mpp_write_meta(unit,x_axes(j),axisname,'none',axisname, &
3439  data=axisdata(1:siz_x_axes(j)),cartesian='X')
3440  end do
3441 
3442 ! write out y_axes metadata
3443  naxes_y = 0
3444  do j = 1, num_y_axes
3445  ! make sure this axis is used by some variable
3446  do l=1, fileobj%nvar
3447  if(fileobj%var(l)%read_only) cycle
3448  if (fileobj%var(l)%id_axes(2) == j) exit
3449  end do
3450  if( l > fileobj%nvar ) cycle
3451  naxes_y = naxes_y + 1
3452  y_axes_indx(naxes_y) = j
3453  if (naxes_y < 10) then
3454  write(axisname,'(a,i1)') 'yaxis_',naxes_y
3455  else
3456  write(axisname,'(a,i2)') 'yaxis_',naxes_y
3457  endif
3458  call mpp_write_meta(unit,y_axes(j),axisname,'none',axisname, &
3459  data=axisdata(1:siz_y_axes(j)),cartesian='Y')
3460  end do
3461 
3462 ! write out z_axes metadata
3463  naxes_z = 0
3464  do j = 1, num_z_axes
3465  ! make sure this axis is used by some variable
3466  do l=1, fileobj%nvar
3467  if(fileobj%var(l)%read_only) cycle
3468  if (fileobj%var(l)%id_axes(3) == j) exit
3469  end do
3470  if( l > fileobj%nvar ) cycle
3471  naxes_z = naxes_z + 1
3472  z_axes_indx(naxes_z) = j
3473  if (naxes_z < 10) then
3474  write(axisname,'(a,i1)') 'zaxis_',naxes_z
3475  else
3476  write(axisname,'(a,i2)') 'zaxis_',naxes_z
3477  endif
3478  call mpp_write_meta(unit,z_axes(j),axisname,'none',axisname, &
3479  data=axisdata(1:siz_z_axes(j)),cartesian='Z')
3480  end do
3481 
3482 ! write out time axis
3483  call mpp_write_meta(unit,t_axes,'Time','time level', &
3484  'Time',cartesian='T')
3485 
3486 ! write metadata for fields
3487  do j = 1, fileobj%nvar
3488  cur_var => fileobj%var(j)
3489  if(cur_var%read_only) cycle
3490  if ((cur_var%siz(4) > 1) .AND. (cur_var%siz(4).NE.fileobj%max_ntime)) call mpp_error(fatal, &
3491  "fms_io(save_restart_border): "//trim(cur_var%name)//" in file "//trim(fileobj%name)// &
3492  " has more than one time level, but number of time level is not equal to max_ntime")
3493 
3494  if (cur_var%ndim == 2) then
3495  num_var_axes = 2
3496  var_axes(1) = x_axes(cur_var%id_axes(1))
3497  var_axes(2) = y_axes(cur_var%id_axes(2))
3498  if(cur_var%siz(4) == fileobj%max_ntime) then
3499  num_var_axes = 3
3500  var_axes(3) = t_axes
3501  end if
3502  else if (cur_var%ndim == 3) then
3503  num_var_axes = 3
3504  var_axes(1) = x_axes(cur_var%id_axes(1))
3505  var_axes(2) = y_axes(cur_var%id_axes(2))
3506  var_axes(3) = z_axes(cur_var%id_axes(3))
3507  if(cur_var%siz(4) == fileobj%max_ntime) then
3508  num_var_axes = 4
3509  var_axes(4) = t_axes
3510  end if
3511  else
3512  call mpp_error(fatal, "fms_io(save_restart_border): "//trim(cur_var%name)//" in file "// &
3513  trim(fileobj%name)//" has more than three dimension (not including time level)")
3514  end if
3515 
3516 ! cycle the loop for pes not a member of the current pelist
3517  if (.not.any(mpp_pe().eq.cur_var%pelist(:))) cycle
3518 
3519 ! IN ORDER TO GET CHECKSUM INFO, PERFORM THE GATHER AS IF YOU WILL BE DOING THE WRITE
3520 ! BUT INSTEAD CHECKSUM THE RESULTING TEMPORARY ARRAY
3521  allocate(check_val(max(1,cur_var%siz(4))))
3522  do k = 1, cur_var%siz(4)
3523 ! cycle the loop for pes not a member of the current pelist
3524  if (.not.any(mpp_pe().eq.cur_var%pelist(:))) cycle
3525  isc = cur_var%is
3526  iec = cur_var%ie
3527  jsc = cur_var%js
3528  jec = cur_var%je
3529 ! set up indices for local array segment pointer (pointer is 1-based)
3530  i1 = 1 + cur_var%x_halo
3531  i2 = i1 + (iec-isc)
3532  j1 = 1 + cur_var%y_halo
3533  j2 = j1 + (jec-jsc)
3534 ! set up index shifts for global array r*d (1-based, but potentially needs offsets: i_add, j_add)
3535  i_add = cur_var%ishift
3536  j_add = cur_var%jshift
3537 ! If some fields only have one time level, we do not need to write the second level, just keep
3538 ! the data missing.
3539  if(k <= cur_var%siz(4)) then
3540  if ( Associated(fileobj%p2dr(k,j)%p) ) then
3541  i_glob = cur_var%gsiz(1)
3542  j_glob = cur_var%gsiz(2)
3543  if (fileobj%is_root_pe) allocate(r2d(i_glob, j_glob))
3544  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, cur_var%pelist, &
3545  fileobj%p2dr(k,j)%p(i1:i2,j1:j2), &
3546  r2d, fileobj%is_root_pe)
3547  check_val(k) = mpp_chksum(r2d, (/mpp_pe()/))
3548  if (allocated(r2d)) deallocate(r2d)
3549  else if ( Associated(fileobj%p3dr(k,j)%p) ) then
3550  i_glob = cur_var%gsiz(1)
3551  j_glob = cur_var%gsiz(2)
3552  k_glob = cur_var%gsiz(3)
3553  if (fileobj%is_root_pe) allocate(r3d(i_glob, j_glob, k_glob))
3554  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, k_glob, cur_var%pelist, &
3555  fileobj%p3dr(k,j)%p(i1:i2,j1:j2,:), r3d, fileobj%is_root_pe)
3556  check_val(k) = mpp_chksum(r3d, (/mpp_pe()/))
3557  if (allocated(r3d)) deallocate(r3d)
3558  else
3559  call mpp_error(fatal, "fms_io(save_restart_border): no pointer associated with data of field "// &
3560  trim(cur_var%name)//" in file "//trim(fileobj%name) )
3561  end if
3562  end if
3563  enddo ! end k loop
3564  call mpp_write_meta(unit,cur_var%field, var_axes(1:num_var_axes), cur_var%name, &
3565  cur_var%units,cur_var%longname,pack=pack_size,checksum=check_val)
3566  if (allocated(check_val)) deallocate(check_val)
3567  enddo
3568 
3569 ! write values for ndim of spatial axes
3570  do j = 1, naxes_x
3571  call mpp_write(unit,x_axes(x_axes_indx(j)))
3572  enddo
3573  do j = 1, naxes_y
3574  call mpp_write(unit,y_axes(y_axes_indx(j)))
3575  enddo
3576  do j = 1, naxes_z
3577  call mpp_write(unit,z_axes(z_axes_indx(j)))
3578  enddo
3579 
3580 ! write data of each field
3581  do k = 1, fileobj%max_ntime
3582  tlev=k
3583  do j=1, fileobj%nvar
3584  cur_var => fileobj%var(j)
3585  if(cur_var%read_only) cycle
3586 ! cycle the loop for pes not a member of the current pelist
3587  if (.not.any(mpp_pe().eq.cur_var%pelist(:))) cycle
3588  isc = cur_var%is
3589  iec = cur_var%ie
3590  jsc = cur_var%js
3591  jec = cur_var%je
3592 ! set up indices for local array segment pointer (pointer is 1-based)
3593  i1 = 1 + cur_var%x_halo
3594  i2 = i1 + (iec-isc)
3595  j1 = 1 + cur_var%y_halo
3596  j2 = j1 + (jec-jsc)
3597 ! set up index shifts for global array r*d (1-based, but potentially needs offsets: i_add, j_add)
3598  i_add = cur_var%ishift
3599  j_add = cur_var%jshift
3600 ! If some fields only have one time level, we do not need to write the second level, just keep
3601 ! the data missing.
3602  if(k <= cur_var%siz(4)) then
3603  if (Associated(fileobj%p2dr(k,j)%p)) then
3604  i_glob = cur_var%gsiz(1)
3605  j_glob = cur_var%gsiz(2)
3606  if (fileobj%is_root_pe) allocate(r2d(i_glob, j_glob))
3607  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, cur_var%pelist, &
3608  fileobj%p2dr(k,j)%p(i1:i2,j1:j2), r2d, fileobj%is_root_pe)
3609  call mpp_write(unit, cur_var%field, r2d, tlev)
3610  if (allocated(r2d)) deallocate(r2d)
3611  else if (Associated(fileobj%p3dr(k,j)%p)) then
3612  i_glob = cur_var%gsiz(1)
3613  j_glob = cur_var%gsiz(2)
3614  k_glob = cur_var%gsiz(3)
3615  if (fileobj%is_root_pe) allocate(r3d(i_glob, j_glob, k_glob))
3616  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, k_glob, cur_var%pelist, &
3617  fileobj%p3dr(k,j)%p(i1:i2,j1:j2,:), r3d, fileobj%is_root_pe)
3618  call mpp_write(unit, cur_var%field, r3d, tlev)
3619  if (allocated(r3d)) deallocate(r3d)
3620  else
3621  call mpp_error(fatal, "fms_io(save_restart_border): no pointer associated with data of field "// &
3622  trim(cur_var%name)//" in file "//trim(fileobj%name) )
3623  end if
3624  end if
3625  enddo ! end j loop
3626  enddo ! end k loop
3627  call mpp_close(unit)
3628 
3629  cur_var =>null()
3630 
3631  if(print_chksum) call write_chksum(fileobj, mpp_overwr)
3632  return
3633 
3634 end subroutine save_restart_border
3635 
3636 
3637 !-------------------------------------------------------------------------------
3638 !
3639 ! restores all registered border/halo variables to restart files. Those
3640 ! variables are set through register_restart_field (region option)
3641 !
3642 !-------------------------------------------------------------------------------
3643 subroutine restore_state_border(fileObj, directory, nonfatal_missing_files)
3644  type(restart_file_type), intent(inout) :: fileobj !< The restart_file_type object that has
3645  !! information about the restarts
3646  character(len=*), optional, intent(in) :: directory !< The directory in which to seek restart files
3647  logical, optional, intent(in) :: nonfatal_missing_files !< If true, the inability to find
3648  !! the expected restart file is not necessarily fatal
3649 ! Arguments:
3650 ! (in) directory - The directory where the restart or save
3651 ! files should be found. The default is 'INPUT'
3652  character(len=128) :: dir
3653  character(len=256) :: restartpath ! The restart file path (dir/file).
3654  character(len=200) :: filepath ! The path (dir/file) to the file being opened.
3655  character(len=80) :: varname ! A variable's name.
3656  character(len=256) :: mesg ! Message to be constructed for checksum error.
3657  type(var_type), pointer, save :: cur_var=>null()
3658  integer :: ndim, nvar, natt, ntime, tlev, siz
3659  type(fieldtype), allocatable :: fields(:)
3660  logical :: fexist
3661  integer :: j, n, l, k, unit
3662  real, allocatable, dimension(:,:,:) :: r3d
3663  real, allocatable, dimension(:,:) :: r2d
3664  integer :: isc, iec, jsc, jec
3665  logical :: check_exist
3666  integer :: i1, i2, j1, j2
3667  integer :: ishift, jshift, i_add, j_add
3668  integer :: i_glob, j_glob, k_glob
3669  integer(LONG_KIND), dimension(3) :: checksum_file
3670  integer(LONG_KIND) :: checksum_data
3671  logical :: is_there_a_checksum
3672  logical :: fatal_missing_files
3673 
3674  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(restore_state_border): " // &
3675  "restart_file_type data must be initialized by calling register_restart_field before using it")
3676 
3677  dir = 'INPUT'
3678  if(present(directory)) dir = directory
3679 
3680  fatal_missing_files = .true.
3681  if (present(nonfatal_missing_files)) fatal_missing_files = .not.nonfatal_missing_files
3682 
3683  if(len_trim(dir) > 0) then
3684  restartpath = trim(dir)//"/"// trim(fileobj%name)
3685  else
3686  restartpath = trim(fileobj%name)
3687  end if
3688 
3689 !--- first open the restart files
3690 !--- NOTE: For distributed restart files, we are assuming there is only one file that might exist.
3691 
3692  inquire (file=trim(restartpath), exist=fexist)
3693  if (.not.fexist) then ; if (fatal_missing_files) then
3694  call mpp_error(fatal, "fms_io(restore_state_border): unable to find any restart files "// &
3695  "specified by "//trim(restartpath))
3696  elseif (mpp_pe() == mpp_root_pe()) then
3697  call mpp_error(warning, "fms_io(restore_state_border): unable to find any restart files "// &
3698  "specified by "//trim(restartpath))
3699  endif ; endif
3700 
3701  if (fexist) then
3702  call mpp_open(unit,trim(restartpath),action=mpp_rdonly,form=mpp_netcdf,threading=mpp_single,&
3703  fileset=mpp_single, is_root_pe=fileobj%is_root_pe)
3704 
3705  ! Read each variable from the first file in which it is found.
3706  call mpp_get_info(unit, ndim, nvar, natt, ntime)
3707 
3708  allocate(fields(nvar))
3709  call mpp_get_fields(unit,fields(1:nvar))
3710 
3711  do j=1,fileobj%nvar
3712  cur_var => fileobj%var(j)
3713  ! cycle the loop for pes not a member of the current pelist
3714  if (.not.any(mpp_pe().eq.cur_var%pelist(:))) cycle
3715  isc = cur_var%is
3716  iec = cur_var%ie
3717  jsc = cur_var%js
3718  jec = cur_var%je
3719  ! set up indices for local array segment pointer (pointer is 1-based)
3720  i1 = 1 + cur_var%x_halo
3721  i2 = i1 + (iec-isc)
3722  j1 = 1 + cur_var%y_halo
3723  j2 = j1 + (jec-jsc)
3724  ! set up index shifts for global array r*d (1-based, but potentially needs offsets: i_add, j_add)
3725  i_add = cur_var%ishift
3726  j_add = cur_var%jshift
3727  do l=1, nvar
3728  call mpp_get_atts(fields(l),name=varname)
3729  if (lowercase(trim(varname)) == lowercase(trim(cur_var%name))) then
3730  cur_var%initialized = .true.
3731  check_exist = mpp_attribute_exist(fields(l),"checksum")
3732  checksum_file = 0
3733  is_there_a_checksum = .false.
3734  if ( check_exist ) then
3735  call mpp_get_atts(fields(l),checksum=checksum_file)
3736  is_there_a_checksum = .true.
3737  endif
3738  if (.NOT. checksum_required) is_there_a_checksum = .false. ! Do not need to do data checksumming.
3739 
3740  do k = 1, cur_var%siz(4)
3741  tlev = k
3742  ! read the field and scatter it to the rest of the pelist
3743  if (Associated(fileobj%p2dr(k,j)%p)) then
3744  i_glob = cur_var%gsiz(1)
3745  j_glob = cur_var%gsiz(2)
3746  if (fileobj%is_root_pe) allocate(r2d(i_glob, j_glob))
3747  call mpp_read(unit, fields(l), r2d, tlev)
3748  call mpp_scatter(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, cur_var%pelist, &
3749  fileobj%p2dr(k,j)%p(i1:i2,j1:j2), r2d, fileobj%is_root_pe)
3750  if ((fileobj%is_root_pe) .and. (is_there_a_checksum)) checksum_data = mpp_chksum(r2d, (/mpp_pe()/) )
3751  if (allocated(r2d)) deallocate(r2d)
3752  else if (Associated(fileobj%p3dr(k,j)%p)) then
3753  i_glob = cur_var%gsiz(1)
3754  j_glob = cur_var%gsiz(2)
3755  k_glob = cur_var%gsiz(3)
3756  if (fileobj%is_root_pe) allocate(r3d(i_glob, j_glob, k_glob))
3757  call mpp_read(unit, fields(l), r3d, tlev)
3758  call mpp_scatter(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, k_glob, cur_var%pelist, &
3759  fileobj%p3dr(k,j)%p(i1:i2,j1:j2,:), r3d, fileobj%is_root_pe)
3760  if ((fileobj%is_root_pe) .and. (is_there_a_checksum)) checksum_data = mpp_chksum(r3d, (/mpp_pe()/) )
3761  if (allocated(r3d)) deallocate(r3d)
3762  else
3763  call mpp_error(fatal, "fms_io(retore_state_border): no pointer associated with data of field "// &
3764  trim(cur_var%name)//" in file "//trim(fileobj%name) )
3765  end if
3766  if ((fileobj%is_root_pe) .and. (is_there_a_checksum) .and. (checksum_file(k)/=checksum_data)) then
3767  write (mesg,'(a,Z16,a,Z16,a)') "Checksum of input field "// uppercase(trim(varname))//" ", checksum_data,&
3768  " does not match value ", checksum_file(k), " stored in "//uppercase(trim(fileobj%name)//"." )
3769  call mpp_error(fatal, "fms_io(restore_state_border): "//trim(mesg) )
3770  endif
3771  end do
3772  exit ! Start search for next restart variable.
3773  endif
3774  enddo
3775  enddo
3776 
3777  deallocate(fields)
3778 
3779  call close_file(unit)
3780  endif ! fexist is true
3781 
3782  cur_var =>null()
3783 
3784  ! check whether all fields have been found
3785  do j = 1, fileobj%nvar
3786  if (.not.any(mpp_pe().eq.fileobj%var(j)%pelist(:))) cycle
3787  if (.NOT. fileobj%var(j)%initialized) then
3788  if (fileobj%var(j)%mandatory) then
3789  call mpp_error(fatal, "fms_io(restore_state_border): unable to find mandatory variable "// &
3790  trim(fileobj%var(j)%name)//" in restart file "//trim(fileobj%name) )
3791  end if
3792  end if
3793  end do
3794 
3795  if(print_chksum) call write_chksum(fileobj, mpp_rdonly )
3796  return
3797 
3798 end subroutine restore_state_border
3799 
3800 !-------------------------------------------------------------------------------
3801 ! This subroutine will calculate chksum and print out chksum information.
3802 !
3803 subroutine write_chksum(fileObj, action)
3804  type(restart_file_type), intent(inout) :: fileObj
3805  integer, intent(in) :: action
3806  integer(LONG_KIND) :: data_chksum
3807  integer :: j, k, outunit
3808  integer :: isc, iec, jsc, jec
3809  integer :: isg, ieg, jsg, jeg
3810  integer :: ishift, jshift, iadd, jadd
3811  type(var_type), pointer, save :: cur_var=>null()
3812  character(len=32) :: routine_name
3813 
3814  if(action == mpp_overwr) then
3815  routine_name = "save_restart"
3816  else if(action == mpp_rdonly) then
3817  routine_name = "restore_state"
3818  else
3819  call mpp_error(fatal, "fms_io_mod(write_chksum): action should be MPP_OVERWR or MPP_RDONLY")
3820  endif
3821 
3822  do j=1,fileobj%nvar
3823  cur_var => fileobj%var(j)
3824 
3825  if ( cur_var%domain_idx > 0) then
3826  call mpp_get_compute_domain(array_domain(cur_var%domain_idx), isc, iec, jsc, jec)
3827  call mpp_get_global_domain(array_domain(cur_var%domain_idx), isg, ieg, jsg, jeg)
3828  call mpp_get_domain_shift(array_domain(cur_var%domain_idx), ishift, jshift, cur_var%position)
3829  else if (ASSOCIATED(current_domain)) then
3830  call mpp_get_compute_domain(current_domain, isc, iec, jsc, jec)
3831  call mpp_get_global_domain(current_domain, isg, ieg, jsg, jeg)
3832  call mpp_get_domain_shift(current_domain, ishift, jshift, cur_var%position)
3833  else
3834  iec = cur_var%ie
3835  isc = cur_var%is
3836  ieg = cur_var%ie
3837  jec = cur_var%je
3838  jsc = cur_var%js
3839  jeg = cur_var%je
3840  ishift = 0
3841  jshift = 0
3842  endif
3843  iadd = iec-isc ! Size of the i-dimension on this processor (-1 as it is an increment)
3844  jadd = jec-jsc ! Size of the j-dimension on this processor
3845  if(iec == ieg) iadd = iadd + ishift
3846  if(jec == jeg) jadd = jadd + jshift
3847 
3848  if(action == mpp_overwr .OR. (action == mpp_rdonly .AND. cur_var%initialized) ) then
3849  do k = 1, cur_var%siz(4)
3850  if ( Associated(fileobj%p0dr(k,j)%p) ) then
3851  data_chksum = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/) )
3852  else if ( Associated(fileobj%p1dr(k,j)%p) ) then
3853  data_chksum = mpp_chksum(fileobj%p1dr(k,j)%p, (/mpp_pe()/) )
3854  else if ( Associated(fileobj%p2dr(k,j)%p) ) then
3855  data_chksum = mpp_chksum(fileobj%p2dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
3856  else if ( Associated(fileobj%p3dr(k,j)%p) ) then
3857  data_chksum = mpp_chksum(fileobj%p3dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :) )
3858  else if ( Associated(fileobj%p4dr(k,j)%p) ) then
3859  data_chksum = mpp_chksum(fileobj%p4dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :, :) )
3860  else if ( Associated(fileobj%p0di(k,j)%p) ) then
3861  data_chksum = fileobj%p0di(k,j)%p
3862  else if ( Associated(fileobj%p1di(k,j)%p) ) then
3863  data_chksum = mpp_chksum(fileobj%p1di(k,j)%p, (/mpp_pe()/) )
3864  else if ( Associated(fileobj%p2di(k,j)%p) ) then
3865  data_chksum = mpp_chksum(fileobj%p2di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
3866  else if ( Associated(fileobj%p3di(k,j)%p) ) then
3867  data_chksum = mpp_chksum(fileobj%p3di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :))
3868  else
3869  call mpp_error(fatal, "fms_io(write_chksum): There is no pointer associated with the data of field "// &
3870  trim(cur_var%name)//" of file "//trim(fileobj%name) )
3871  end if
3872  outunit = stdout()
3873  write(outunit,'(a, I1, a, Z16)')'fms_io('//trim(routine_name)//'): At time level = ', k, ', chksum for "'// &
3874  trim(cur_var%name)// '" of "'// trim(fileobj%name)// '" = ', data_chksum
3875 
3876  enddo
3877  endif
3878  enddo
3879  cur_var =>null()
3880 
3881 end subroutine write_chksum
3882 
3883 !-------------------------------------------------------------------------------
3884 !
3885 ! This subroutine reads the model state from previously
3886 ! generated files. All restart variables are read from the first
3887 ! file in the input filename list in which they are found.
3888 
3889 subroutine restore_state_all(fileObj, directory, nonfatal_missing_files)
3890  type(restart_file_type), intent(inout) :: fileObj !< The restart_file_type object that has
3891  !! information about the restarts
3892  character(len=*), optional, intent(in) :: directory !< The directory in which to seek restart files
3893  logical, optional, intent(in) :: nonfatal_missing_files !< If true, the inability to find
3894  !! the expected restart file is not necessarily fatal
3895 
3896 ! Arguments:
3897 ! (in) directory - The directory where the restart or save
3898 ! files should be found. The default is 'INPUT'
3899 
3900  character(len=128) :: dir
3901  character(len=256) :: restartpath ! The restart file path (dir/file).
3902  character(len=200) :: filepath ! The path (dir/file) to the file being opened.
3903  character(len=8) :: suffix ! A suffix (like "_2") that is added to any
3904  ! additional restart files.
3905  character(len=80) :: varname ! A variable's name.
3906  character(len=256) :: filename
3907  character(len=256) :: mesg ! Message to be constructed for checksum error.
3908  integer :: num_restart ! The number of restart files that have already
3909  ! been opened.
3910  integer :: nfile ! The number of files (restart files and others
3911  ! explicitly in filename) that are open.
3912  integer :: unit(max_split_file) ! The mpp unit of all open files.
3913  type(var_type), pointer, save :: cur_var=>null()
3914  integer :: ndim, nvar, natt, ntime, tlev, siz
3915  type(fieldtype), allocatable :: fields(:)
3916  logical :: fexist, domain_present
3917  integer :: j, n, l, k, missing_fields, domain_idx
3918  integer :: tile_id(1)
3919  real, allocatable, dimension(:,:,:) :: r3d
3920  real, allocatable, dimension(:,:) :: r2d
3921  real, allocatable, dimension(:) :: r1d
3922  real :: r0d
3923  type(domain2d), pointer, save :: io_domain=>null()
3924  integer :: isc, iec, jsc, jec
3925  logical :: check_exist
3926  integer :: isg, ieg, jsg, jeg
3927  integer :: ishift, jshift, iadd, jadd
3928  integer(LONG_KIND), dimension(3) :: checksum_file
3929  integer(LONG_KIND) :: checksum_data
3930  logical :: is_there_a_checksum
3931  logical :: fatal_missing_files
3932 
3933  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(restore_state_all): " // &
3934  "restart_file_type data must be initialized by calling register_restart_field before using it")
3935 
3936  dir = 'INPUT'
3937  if(present(directory)) dir = directory
3938 
3939  fatal_missing_files = .true.
3940  if (present(nonfatal_missing_files)) fatal_missing_files = .not.nonfatal_missing_files
3941 
3942  num_restart = 0
3943  nfile = 0
3944  if(len_trim(dir) > 0) then
3945  restartpath = trim(dir)//"/"// trim(fileobj%name)
3946  else
3947  restartpath = trim(fileobj%name)
3948  end if
3949 
3950  domain_present = .false.
3951  do j = 1, fileobj%nvar
3952  if (fileobj%var(j)%domain_present) then
3953  domain_present = .true.
3954  domain_idx = fileobj%var(j)%domain_idx
3955  exit
3956  end if
3957  end do
3958 
3959  !--- first open all the restart files
3960  !--- NOTE: For distributed restart file, we are assuming there is only one file exist.
3961  fexist = .false.
3962  if(domain_present) then
3963  io_domain => mpp_get_io_domain(array_domain(domain_idx))
3964  if(associated(io_domain)) then
3965  tile_id = mpp_get_tile_id(io_domain)
3966  write(filename, '(a,i4.4)' ) trim(restartpath)//'.', tile_id(1)
3967  inquire (file=trim(filename), exist = fexist)
3968  if( .NOT. fexist ) then
3969  write(filename, '(a,i6.6)' ) trim(restartpath)//'.', tile_id(1)
3970  inquire (file=trim(filename), exist = fexist)
3971  endif
3972  endif
3973  io_domain => null()
3974  endif
3975  if(fexist) then
3976  nfile = 1
3977  !--- domain_present is true
3978  call mpp_open(unit(nfile), trim(restartpath), form=form,action=mpp_rdonly, &
3979  threading=mpp_multi, domain=array_domain(domain_idx) )
3980  else
3981  do while(.true.)
3982  if (num_restart < 10) then
3983  write(suffix,'("_",I1)') num_restart
3984  else
3985  write(suffix,'("_",I2)') num_restart
3986  endif
3987  if (num_restart > 0) then
3988  siz = len_trim(restartpath)
3989  if(restartpath(siz-2:siz) == ".nc") then
3990  filepath = restartpath(1:siz-3)//trim(suffix)
3991  else
3992  filepath = trim(restartpath) // trim(suffix)
3993  end if
3994  else
3995  filepath = trim(restartpath)
3996  end if
3997  inquire (file=trim(filepath), exist=fexist)
3998  if(.not. fexist) inquire(file=trim(filepath)//".nc", exist=fexist)
3999  if(fexist) then
4000  nfile = nfile + 1
4001  if(nfile > max_split_file) call mpp_error(fatal, &
4002  "fms_io(restore_state_all): nfile is larger than max_split_file, increase max_split_file")
4003  call mpp_open(unit(nfile), trim(filepath), form=form,action=mpp_rdonly,threading=mpp_multi, &
4004  fileset=mpp_single)
4005  else
4006  exit
4007  end if
4008  num_restart = num_restart + 1
4009  end do
4010  end if
4011  if (nfile == 0) then ; if (fatal_missing_files) then
4012  call mpp_error(fatal, "fms_io(restore_state_all): unable to find any restart files "// &
4013  "specified by "//trim(restartpath))
4014  elseif (mpp_pe() == mpp_root_pe()) then
4015  call mpp_error(warning, "fms_io(restore_state_all): unable to find any restart files "// &
4016  "specified by "//trim(restartpath))
4017  endif ; endif
4018 
4019 
4020  ! Read each variable from the first file in which it is found.
4021  do n=1,nfile
4022  call mpp_get_info(unit(n), ndim, nvar, natt, ntime)
4023 
4024  allocate(fields(nvar))
4025  call mpp_get_fields(unit(n),fields(1:nvar))
4026 
4027  missing_fields = 0
4028 
4029  do j=1,fileobj%nvar
4030  cur_var => fileobj%var(j)
4031  domain_present = cur_var%domain_present
4032  domain_idx = cur_var%domain_idx
4033 
4034  if ( cur_var%domain_idx > 0) then
4035  call mpp_get_compute_domain(array_domain(cur_var%domain_idx), isc, iec, jsc, jec)
4036  call mpp_get_global_domain(array_domain(cur_var%domain_idx), isg, ieg, jsg, jeg)
4037  call mpp_get_domain_shift(array_domain(cur_var%domain_idx), ishift, jshift, cur_var%position)
4038  else if (ASSOCIATED(current_domain)) then
4039  call mpp_get_compute_domain(current_domain, isc, iec, jsc, jec)
4040  call mpp_get_global_domain(current_domain, isg, ieg, jsg, jeg)
4041  call mpp_get_domain_shift(current_domain, ishift, jshift, cur_var%position)
4042  else
4043  iec = cur_var%ie
4044  isc = cur_var%is
4045  ieg = cur_var%ie
4046  jec = cur_var%je
4047  jsc = cur_var%js
4048  jeg = cur_var%je
4049  ishift = 0
4050  jshift = 0
4051  endif
4052  iadd = iec-isc ! Size of the i-dimension on this processor (-1 as it is an increment)
4053  jadd = jec-jsc ! Size of the j-dimension on this processor
4054  if(iec == ieg) iadd = iadd + ishift
4055  if(jec == jeg) jadd = jadd + jshift
4056 
4057  isc = cur_var%is
4058  iec = cur_var%ie
4059  jsc = cur_var%js
4060  jec = cur_var%je
4061  do l=1, nvar
4062  call mpp_get_atts(fields(l),name=varname)
4063  if (lowercase(trim(varname)) == lowercase(trim(cur_var%name))) then
4064  cur_var%initialized = .true.
4065  check_exist = mpp_attribute_exist(fields(l),"checksum")
4066  checksum_file = 0
4067  is_there_a_checksum = .false.
4068  if ( check_exist ) then
4069  call mpp_get_atts(fields(l),checksum=checksum_file)
4070  is_there_a_checksum = .true.
4071  endif
4072  if (.NOT. checksum_required ) is_there_a_checksum = .false. ! Do not need to do data checksumming.
4073 
4074  do k = 1, cur_var%siz(4)
4075  tlev = k
4076  if(domain_present) then
4077  if( Associated(fileobj%p0dr(k,j)%p) ) then
4078  call mpp_read(unit(n), fields(l), fileobj%p0dr(k,j)%p, tlev)
4079  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/) )
4080  else if( Associated(fileobj%p1dr(k,j)%p) ) then
4081  call mpp_read(unit(n), fields(l), fileobj%p1dr(k,j)%p, tlev)
4082  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1dr(k,j)%p, (/mpp_pe()/) )
4083  else if( Associated(fileobj%p2dr(k,j)%p) ) then
4084  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p2dr(k,j)%p, tlev)
4085  if ( is_there_a_checksum ) &
4086  checksum_data = mpp_chksum(fileobj%p2dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4087  else if( Associated(fileobj%p3dr(k,j)%p) ) then
4088  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p3dr(k,j)%p, tlev)
4089  if ( is_there_a_checksum ) &
4090  checksum_data = mpp_chksum(fileobj%p3dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :) )
4091  else if( Associated(fileobj%p2dr8(k,j)%p) ) then
4092  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p2dr8(k,j)%p, tlev)
4093  if ( is_there_a_checksum ) &
4094  checksum_data = mpp_chksum(fileobj%p2dr8(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4095  else if( Associated(fileobj%p3dr8(k,j)%p) ) then
4096  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p3dr8(k,j)%p, tlev)
4097  if ( is_there_a_checksum ) &
4098  checksum_data = mpp_chksum(fileobj%p3dr8(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :) )
4099  else if( Associated(fileobj%p4dr(k,j)%p) ) then
4100  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p4dr(k,j)%p, tlev)
4101  if ( is_there_a_checksum ) &
4102  checksum_data = mpp_chksum(fileobj%p4dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd,:,:))
4103  else if( Associated(fileobj%p0di(k,j)%p) ) then
4104  call mpp_read(unit(n), fields(l), r0d, tlev)
4105  fileobj%p0di(k,j)%p = r0d
4106  if ( is_there_a_checksum ) checksum_data = fileobj%p0di(k,j)%p
4107  else if( Associated(fileobj%p1di(k,j)%p) ) then
4108  allocate(r1d(cur_var%siz(1)))
4109  call mpp_read(unit(n), fields(l), r1d, tlev)
4110  fileobj%p1di(k,j)%p = r1d
4111  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1di(k,j)%p, (/mpp_pe()/) )
4112  deallocate(r1d)
4113  else if( Associated(fileobj%p2di(k,j)%p) ) then
4114  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
4115  r2d = 0
4116  call mpp_read(unit(n), fields(l), array_domain(domain_idx), r2d, tlev)
4117  fileobj%p2di(k,j)%p(isc:iec,jsc:jec) = r2d(isc:iec,jsc:jec)
4118  if ( is_there_a_checksum ) &
4119  checksum_data = mpp_chksum(fileobj%p2di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4120  deallocate(r2d)
4121  else if( Associated(fileobj%p3di(k,j)%p) ) then
4122  allocate(r3d(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3)) )
4123  r3d = 0
4124  call mpp_read(unit(n), fields(l), array_domain(domain_idx), r3d, tlev)
4125  fileobj%p3di(k,j)%p(isc:iec,jsc:jec,:) = r3d(isc:iec,jsc:jec,:)
4126  if ( is_there_a_checksum ) &
4127  checksum_data = mpp_chksum(fileobj%p3di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :))
4128  deallocate(r3d)
4129  else
4130  call mpp_error(fatal, "fms_io(restore_state_all): domain is present for the field "//trim(varname)// &
4131  " of file "//trim(fileobj%name)//", but none of p2dr, p3dr, p2di and p3di is associated")
4132  end if
4133  else
4134  if( Associated(fileobj%p0dr(k,j)%p) ) then
4135  call mpp_read(unit(n), fields(l), fileobj%p0dr(k,j)%p, tlev)
4136  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/) )
4137  else if( Associated(fileobj%p1dr(k,j)%p) ) then
4138  call mpp_read(unit(n), fields(l), fileobj%p1dr(k,j)%p, tlev)
4139  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1dr(k,j)%p, (/mpp_pe()/) )
4140  else if( Associated(fileobj%p2dr(k,j)%p) ) then
4141  call mpp_read(unit(n), fields(l), fileobj%p2dr(k,j)%p, tlev)
4142  if ( is_there_a_checksum ) &
4143  checksum_data = mpp_chksum(fileobj%p2dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4144  else if( Associated(fileobj%p3dr(k,j)%p) ) then
4145  call mpp_read(unit(n), fields(l), fileobj%p3dr(k,j)%p, tlev)
4146  if ( is_there_a_checksum ) &
4147  checksum_data = mpp_chksum(fileobj%p3dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :) )
4148  else if( Associated(fileobj%p4dr(k,j)%p) ) then
4149  call mpp_read(unit(n), fields(l), fileobj%p4dr(k,j)%p, tlev)
4150  if ( is_there_a_checksum ) &
4151  checksum_data = mpp_chksum(fileobj%p4dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd,:,:))
4152  else if( Associated(fileobj%p0di(k,j)%p) ) then
4153  call mpp_read(unit(n), fields(l), r0d, tlev)
4154  fileobj%p0di(k,j)%p = r0d
4155  if ( is_there_a_checksum ) checksum_data = fileobj%p0di(k,j)%p
4156  else if( Associated(fileobj%p1di(k,j)%p) ) then
4157  allocate(r1d(cur_var%siz(1)) )
4158  call mpp_read(unit(n), fields(l), r1d, tlev)
4159  fileobj%p1di(k,j)%p = r1d
4160  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1di(k,j)%p, (/mpp_pe()/) )
4161  deallocate(r1d)
4162  else if( Associated(fileobj%p2di(k,j)%p) ) then
4163  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
4164  r2d = 0
4165  call mpp_read(unit(n), fields(l), r2d, tlev)
4166  fileobj%p2di(k,j)%p = r2d
4167  if ( is_there_a_checksum ) &
4168  checksum_data = mpp_chksum(fileobj%p2di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4169  deallocate(r2d)
4170  else if( Associated(fileobj%p3di(k,j)%p) ) then
4171  allocate(r3d(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3)) )
4172  r3d = 0
4173  call mpp_read(unit(n), fields(l), r3d, tlev)
4174  fileobj%p3di(k,j)%p = r3d
4175  if ( is_there_a_checksum ) &
4176  checksum_data = mpp_chksum(fileobj%p3di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :))
4177  deallocate(r3d)
4178  else
4179  call mpp_error(fatal, "fms_io(restore_state_all): There is no pointer "//&
4180  "associated with the data of field "// trim(varname)//" of file "//trim(fileobj%name) )
4181  end if
4182  end if
4183  if ( ( is_there_a_checksum ) .and. (checksum_file(k) /= checksum_data) ) then
4184  write (mesg,'(a,Z16,a,Z16,a)') "Checksum of input field "// uppercase(trim(varname))//" ", checksum_data,&
4185  " does not match value ", checksum_file(k), " stored in "//uppercase(trim(fileobj%name)//"." )
4186  call mpp_error(fatal, "fms_io(restore_state_all): "//trim(mesg) )
4187  endif
4188  end do
4189  exit ! Start search for next restart variable.
4190  endif
4191  enddo
4192  if (l>nvar) missing_fields = missing_fields+1
4193  enddo
4194 
4195  deallocate(fields)
4196  if (missing_fields == 0) exit
4197  enddo
4198 
4199  do n=1,nfile
4200  call close_file(unit(n))
4201  enddo
4202 
4203  ! check whether all fields have been found
4204  do j = 1, fileobj%nvar
4205  if( .NOT. fileobj%var(j)%initialized ) then
4206  if( fileobj%var(j)%mandatory ) then
4207  call mpp_error(fatal, "fms_io(restore_state_all): unable to find mandatory variable "// &
4208  trim(fileobj%var(j)%name)//" in restart file "//trim(fileobj%name) )
4209  end if
4210  end if
4211  end do
4212  cur_var =>null()
4213 
4214  if(print_chksum) call write_chksum(fileobj, mpp_rdonly )
4215 
4216 end subroutine restore_state_all
4217 
4218 !-------------------------------------------------------------------------------
4219 !
4220 ! This subroutine reads the model state from previously
4221 ! generated files. All restart variables are read from the first
4222 ! file in the input filename list in which they are found.
4223 
4224 subroutine restore_state_one_field(fileObj, id_field, directory, nonfatal_missing_files)
4225  type(restart_file_type), intent(inout) :: fileObj !< The restart_file_type object that has
4226  !! information about the restarts
4227  integer, intent(in) :: id_field !< The field id of a variable that was
4228  !! returned by a previous call to register_restart_field
4229  character(len=*), optional, intent(in) :: directory !< The directory in which to seek restart files
4230  logical, optional, intent(in) :: nonfatal_missing_files !< If true, the inability to find
4231  !! the expected restart file is not necessarily fatal
4232 
4233 ! Arguments:
4234 ! (in) directory - The directory where the restart or save
4235 ! files should be found. The default is 'INPUT'
4236 
4237  character(len=128) :: dir
4238  character(len=256) :: restartpath ! The restart file path (dir/file).
4239  character(len=200) :: filepath ! The path (dir/file) to the file being opened.
4240  character(len=8) :: suffix ! A suffix (like "_2") that is added to any
4241  ! additional restart files.
4242  character(len=80) :: varname ! A variable's name.
4243  character(len=256) :: filename
4244  character(len=256) :: mesg ! Message to be constructed for checksum error.
4245  integer :: num_restart ! The number of restart files that have already
4246  ! been opened.
4247  integer :: nfile ! The number of files (restart files and others
4248  ! explicitly in filename) that are open.
4249  integer :: unit(max_split_file) ! The mpp unit of all open files.
4250  type(var_type), pointer, save :: cur_var=>null()
4251  integer :: ndim, nvar, natt, ntime, tlev, siz
4252  integer :: tile_id(1)
4253  type(fieldtype), allocatable :: fields(:)
4254  logical :: fexist, domain_present
4255  integer :: j, n, l, k, missing_fields, domain_idx
4256  real, allocatable, dimension(:,:,:) :: r3d
4257  real, allocatable, dimension(:,:) :: r2d
4258  real, allocatable, dimension(:) :: r1d
4259  real :: r0d
4260  type(domain2d), pointer, save :: io_domain=>null()
4261  integer :: isc, iec, jsc, jec
4262  logical :: check_exist
4263  integer :: isg, ieg, jsg, jeg
4264  integer :: ishift, jshift, iadd, jadd
4265  integer(LONG_KIND), dimension(3) :: checksum_file ! There should be no more than 3 timelevels in a restart file.
4266  integer(LONG_KIND) :: checksum_data
4267  logical :: is_there_a_checksum
4268  logical :: fatal_missing_files
4269 
4270  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(restore_state_one_field): " // &
4271  "restart_file_type data must be initialized by calling register_restart_field before using it")
4272 
4273  dir = 'INPUT'
4274  if(present(directory)) dir = directory
4275 
4276  fatal_missing_files = .true.
4277  if (present(nonfatal_missing_files)) fatal_missing_files = .not.nonfatal_missing_files
4278 
4279  cur_var => fileobj%var(id_field)
4280  domain_present = cur_var%domain_present
4281  domain_idx = cur_var%domain_idx
4282 
4283  if ( cur_var%domain_idx > 0) then
4284  call mpp_get_compute_domain(array_domain(cur_var%domain_idx), isc, iec, jsc, jec)
4285  call mpp_get_global_domain(array_domain(cur_var%domain_idx), isg, ieg, jsg, jeg)
4286  call mpp_get_domain_shift(array_domain(cur_var%domain_idx), ishift, jshift, cur_var%position)
4287  else if (ASSOCIATED(current_domain)) then
4288  call mpp_get_compute_domain(current_domain, isc, iec, jsc, jec)
4289  call mpp_get_global_domain(current_domain, isg, ieg, jsg, jeg)
4290  call mpp_get_domain_shift(current_domain, ishift, jshift, cur_var%position)
4291  else
4292  iec = cur_var%ie
4293  isc = cur_var%is
4294  ieg = cur_var%ie
4295  jec = cur_var%je
4296  jsc = cur_var%js
4297  jeg = cur_var%je
4298  ishift = 0
4299  jshift = 0
4300  endif
4301  iadd = iec-isc ! Size of the i-dimension on this processor (-1 as it is an increment)
4302  jadd = jec-jsc ! Size of the j-dimension on this processor
4303  if(iec == ieg) iadd = iadd + ishift
4304  if(jec == jeg) jadd = jadd + jshift
4305 
4306  num_restart = 0
4307  nfile = 0
4308  if(len_trim(dir) > 0) then
4309  restartpath = trim(dir)//"/"// trim(fileobj%name)
4310  else
4311  restartpath = trim(fileobj%name)
4312  end if
4313  !--- first open all the restart files
4314  !--- NOTE: For distributed restart file, we are assuming there is only one file exist.
4315  fexist = .false.
4316  if(domain_present) then
4317  io_domain => mpp_get_io_domain(array_domain(domain_idx))
4318  if(associated(io_domain)) then
4319  tile_id = mpp_get_tile_id(io_domain)
4320  write(filename, '(a,i4.4)' ) trim(restartpath)//'.', tile_id(1)
4321  inquire (file=trim(filename), exist = fexist)
4322  if( .NOT. fexist ) then
4323  write(filename, '(a,i6.6)' ) trim(restartpath)//'.', tile_id(1)
4324  inquire (file=trim(filename), exist = fexist)
4325  endif
4326  endif
4327  io_domain=>null()
4328  endif
4329 
4330  if(fexist) then
4331  nfile = 1
4332  !--- domain_present is true here.
4333  call mpp_open(unit(nfile), trim(restartpath), form=form,action=mpp_rdonly, &
4334  threading=mpp_multi, domain=array_domain(domain_idx) )
4335  else
4336  do while(.true.)
4337  if (num_restart < 10) then
4338  write(suffix,'("_",I1)') num_restart
4339  else
4340  write(suffix,'("_",I2)') num_restart
4341  endif
4342  if (num_restart > 0) then
4343  siz = len_trim(restartpath)
4344  if(restartpath(siz-2:siz) == ".nc") then
4345  filepath = restartpath(1:siz-3)//trim(suffix)
4346  else
4347  filepath = trim(restartpath) // trim(suffix)
4348  end if
4349  else
4350  filepath = trim(restartpath)
4351  end if
4352  inquire (file=trim(filepath), exist=fexist)
4353  if(.not. fexist) inquire(file=trim(filepath)//".nc", exist=fexist)
4354  if(fexist) then
4355  nfile = nfile + 1
4356  if(nfile > max_split_file) call mpp_error(fatal, &
4357  "fms_io(restore_state_one_field): nfile is larger than max_split_file, increase max_split_file")
4358  call mpp_open(unit(nfile), trim(filepath), form=form,action=mpp_rdonly,threading=mpp_multi, &
4359  fileset=mpp_single)
4360  else
4361  exit
4362  end if
4363  num_restart = num_restart + 1
4364  end do
4365  end if
4366  if (nfile == 0) then ; if (fatal_missing_files) then
4367  call mpp_error(fatal, "fms_io(restore_state_all): unable to find any restart files "// &
4368  "specified by "//trim(restartpath))
4369  elseif (mpp_pe() == mpp_root_pe()) then
4370  call mpp_error(warning, "fms_io(restore_state_all): unable to find any restart files "// &
4371  "specified by "//trim(restartpath))
4372  endif ; endif
4373 
4374 
4375  ! Read each variable from the first file in which it is found.
4376  do n=1,nfile
4377  call mpp_get_info(unit(n), ndim, nvar, natt, ntime)
4378 
4379  allocate(fields(nvar))
4380  call mpp_get_fields(unit(n),fields(1:nvar))
4381 
4382  missing_fields = 0
4383  j = id_field
4384  do l=1, nvar
4385  call mpp_get_atts(fields(l),name=varname)
4386  if (lowercase(trim(varname)) == lowercase(trim(cur_var%name))) then
4387  cur_var%initialized = .true.
4388  check_exist = mpp_attribute_exist(fields(l),"checksum")
4389  checksum_file = 0
4390  is_there_a_checksum = .false.
4391  if ( check_exist ) then
4392  call mpp_get_atts(fields(l),checksum=checksum_file)
4393  is_there_a_checksum = .true.
4394  endif
4395  if (.NOT. checksum_required ) is_there_a_checksum = .false. ! Do not need to do data checksumming.
4396  isc = cur_var%is
4397  iec = cur_var%ie
4398  jsc = cur_var%js
4399  jec = cur_var%je
4400  do k = 1, cur_var%siz(4)
4401  tlev = k
4402  if(domain_present) then
4403  if( Associated(fileobj%p0dr(k,j)%p) ) then
4404  call mpp_read(unit(n), fields(l), fileobj%p0dr(k,j)%p, tlev)
4405  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/) )
4406  else if( Associated(fileobj%p1dr(k,j)%p) ) then
4407  call mpp_read(unit(n), fields(l), fileobj%p1dr(k,j)%p, tlev)
4408  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1dr(k,j)%p, (/mpp_pe()/) )
4409  else if( Associated(fileobj%p2dr(k,j)%p) ) then
4410  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p2dr(k,j)%p, tlev)
4411  if ( is_there_a_checksum ) checksum_data =&
4412  & mpp_chksum(fileobj%p2dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4413  else if( Associated(fileobj%p3dr(k,j)%p) ) then
4414  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p3dr(k,j)%p, tlev)
4415  if ( is_there_a_checksum ) checksum_data =&
4416  & mpp_chksum(fileobj%p3dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :) )
4417  else if( Associated(fileobj%p4dr(k,j)%p) ) then
4418  call mpp_read(unit(n), fields(l), array_domain(domain_idx), fileobj%p4dr(k,j)%p, tlev)
4419  if ( is_there_a_checksum ) checksum_data =&
4420  & mpp_chksum(fileobj%p4dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :,:) )
4421  else if( Associated(fileobj%p0di(k,j)%p) ) then
4422  call mpp_read(unit(n), fields(l), r0d, tlev)
4423  fileobj%p0di(k,j)%p = r0d
4424  if ( is_there_a_checksum ) checksum_data = fileobj%p0di(k,j)%p
4425  else if( Associated(fileobj%p1di(k,j)%p) ) then
4426  allocate(r1d(cur_var%siz(1)))
4427  call mpp_read(unit(n), fields(l), r1d, tlev)
4428  fileobj%p1di(k,j)%p = r1d
4429  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1di(k,j)%p, (/mpp_pe()/) )
4430  deallocate(r1d)
4431  else if( Associated(fileobj%p2di(k,j)%p) ) then
4432  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
4433  r2d = 0
4434  call mpp_read(unit(n), fields(l), array_domain(domain_idx), r2d, tlev)
4435  fileobj%p2di(k,j)%p(isc:iec,jsc:jec) = r2d(isc:iec,jsc:jec)
4436  if ( is_there_a_checksum ) checksum_data =&
4437  & mpp_chksum(fileobj%p2di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4438  deallocate(r2d)
4439  else if( Associated(fileobj%p3di(k,j)%p) ) then
4440  allocate(r3d(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3)) )
4441  r3d = 0
4442  call mpp_read(unit(n), fields(l), array_domain(domain_idx), r3d, tlev)
4443  fileobj%p3di(k,j)%p(isc:iec,jsc:jec,:) = r3d(isc:iec,jsc:jec,:)
4444  if ( is_there_a_checksum ) checksum_data =&
4445  & mpp_chksum(fileobj%p3di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :))
4446  deallocate(r3d)
4447  else
4448  call mpp_error(fatal, "fms_io(restore_state_one_field): domain is present for the field "//trim(varname)// &
4449  " of file "//trim(fileobj%name)//", but none of p2dr, p3dr, p2di and p3di is associated")
4450  end if
4451  else
4452  if( Associated(fileobj%p0dr(k,j)%p) ) then
4453  call mpp_read(unit(n), fields(l), fileobj%p0dr(k,j)%p, tlev)
4454  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p0dr(k,j)%p, (/mpp_pe()/) )
4455  else if( Associated(fileobj%p1dr(k,j)%p) ) then
4456  call mpp_read(unit(n), fields(l), fileobj%p1dr(k,j)%p, tlev)
4457  if ( is_there_a_checksum ) checksum_data = mpp_chksum(fileobj%p1dr(k,j)%p, (/mpp_pe()/) )
4458  else if( Associated(fileobj%p2dr(k,j)%p) ) then
4459  call mpp_read(unit(n), fields(l), fileobj%p2dr(k,j)%p, tlev)
4460  if ( is_there_a_checksum ) checksum_data =&
4461  & mpp_chksum(fileobj%p2dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4462  else if( Associated(fileobj%p3dr(k,j)%p) ) then
4463  call mpp_read(unit(n), fields(l), fileobj%p3dr(k,j)%p, tlev)
4464  if ( is_there_a_checksum ) checksum_data =&
4465  & mpp_chksum(fileobj%p3dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :) )
4466  else if( Associated(fileobj%p4dr(k,j)%p) ) then
4467  call mpp_read(unit(n), fields(l), fileobj%p4dr(k,j)%p, tlev)
4468  if ( is_there_a_checksum ) checksum_data =&
4469  & mpp_chksum(fileobj%p4dr(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :, :) )
4470  else if( Associated(fileobj%p0di(k,j)%p) ) then
4471  call mpp_read(unit(n), fields(l), r0d, tlev)
4472  fileobj%p0di(k,j)%p = r0d
4473  if ( is_there_a_checksum ) checksum_data = fileobj%p0di(k,j)%p
4474  else if( Associated(fileobj%p1di(k,j)%p) ) then
4475  allocate(r1d(cur_var%siz(1)) )
4476  call mpp_read(unit(n), fields(l), r1d, tlev)
4477  fileobj%p1di(k,j)%p = r1d
4478  if ( is_there_a_checksum ) checksum_data = fileobj%p0di(k,j)%p
4479  deallocate(r1d)
4480  else if( Associated(fileobj%p2di(k,j)%p) ) then
4481  allocate(r2d(cur_var%siz(1), cur_var%siz(2)) )
4482  r2d = 0
4483  call mpp_read(unit(n), fields(l), r2d, tlev)
4484  fileobj%p2di(k,j)%p = r2d
4485  if ( is_there_a_checksum ) checksum_data =&
4486  & mpp_chksum(fileobj%p2di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd) )
4487  deallocate(r2d)
4488  else if( Associated(fileobj%p3di(k,j)%p) ) then
4489  allocate(r3d(cur_var%siz(1), cur_var%siz(2), cur_var%siz(3)) )
4490  r3d = 0
4491  call mpp_read(unit(n), fields(l), r3d, tlev)
4492  fileobj%p3di(k,j)%p = r3d
4493  if ( is_there_a_checksum ) checksum_data =&
4494  & mpp_chksum(fileobj%p3di(k,j)%p(cur_var%is:cur_var%is+iadd,cur_var%js:cur_var%js+jadd, :))
4495  deallocate(r3d)
4496  else
4497  call mpp_error(fatal, "fms_io(restore_state_one_field): There is no pointer "// &
4498  "associated with the data of field "//trim(varname)//" of file "//trim(fileobj%name) )
4499  end if
4500  end if
4501  if ( (is_there_a_checksum ) .and. (checksum_file(k) /= checksum_data) ) then
4502  write (mesg,'(a,Z16,a,Z16,a)') "Checksum of input field "// uppercase(trim(varname)), checksum_data,&
4503  " does not match value ", checksum_file(k), "stored in "//uppercase(trim(fileobj%name)//"." )
4504  call mpp_error(fatal, "fms_io(restore_state_one_field): "//trim(mesg) )
4505  endif
4506  end do
4507  exit ! Start search for next restart variable.
4508  endif
4509  enddo
4510  if (l>nvar) missing_fields = missing_fields+1
4511  deallocate(fields)
4512  if (missing_fields == 0) exit
4513  enddo
4514 
4515  do n=1,nfile
4516  call close_file(unit(n))
4517  enddo
4518 
4519  ! check whether the field have been found
4520  if( .NOT. fileobj%var(id_field)%initialized ) then
4521  if( fileobj%var(id_field)%mandatory ) then
4522  call mpp_error(fatal, "fms_io(restore_state_one_field): unable to find mandatory variable "// &
4523  trim(fileobj%var(id_field)%name)//" in restart file "//trim(fileobj%name) )
4524  end if
4525  end if
4526  cur_var =>null()
4527 
4528 end subroutine restore_state_one_field
4529 
4530 !-------------------------------------------------------------------------------
4531 !
4532 ! This routine will setup one entry to be written out
4533 !
4534 !-------------------------------------------------------------------------------
4535 subroutine setup_one_field(fileObj, filename, fieldname, field_siz, index_field, domain, mandatory, &
4536  no_domain, scalar_or_1d, position, tile_count, data_default, longname, units, &
4537  compressed_axis, read_only, owns_data)
4538  type(restart_file_type), intent(inout) :: fileObj
4539  character(len=*), intent(in) :: filename, fieldname
4540  integer, dimension(:), intent(in) :: field_siz
4541  integer, intent(out) :: index_field
4542  type(domain2d), optional, intent(in), target :: domain
4543  real, optional, intent(in) :: data_default
4544  logical, optional, intent(in) :: no_domain
4545  logical, optional, intent(in) :: scalar_or_1d
4546  integer, optional, intent(in) :: position, tile_count
4547  logical, optional, intent(in) :: mandatory
4548  character(len=*), optional, intent(in) :: longname, units, compressed_axis
4549  logical, optional, intent(in) :: owns_data !data will be deallocated on dellocation of restart
4550  logical, optional, intent(in) :: read_only !The variable will not be written to restart file.
4551 
4552  !--- local variables
4553  integer :: i, domain_idx
4554  integer :: ishift, jshift
4555  integer :: gxsize, gysize
4556  integer :: cxsize, cysize
4557  integer :: dxsize, dysize
4558  real :: default_data
4559  logical :: is_no_domain = .false.
4560  logical :: is_scalar_or_1d = .false.
4561  character(len=256) :: fname, filename2, append_string
4562  type(domain2d), pointer, save :: d_ptr =>null()
4563  type(var_type), pointer, save :: cur_var =>null()
4564  integer :: length, n_field_siz
4565 
4566  if(any(field_siz < 0)) then
4567  call mpp_error(fatal, "fms_io(setup_one_field): each entry of field_size should be a non-negative integer")
4568  end if
4569 
4570  if(PRESENT(data_default))then
4571  default_data=data_default
4572  else
4573  default_data = mpp_fill_double
4574  endif
4575 
4576  if(present(tile_count) .AND. .not. present(domain)) call mpp_error(fatal, &
4577  'fms_io(setup_one_field): when tile_count is present, domain must be present')
4578 
4579  is_scalar_or_1d = .false.
4580  if(PRESENT(scalar_or_1d)) is_scalar_or_1d = scalar_or_1d
4581 
4582  is_no_domain = .false.
4583  if (PRESENT(no_domain)) THEN
4584  is_no_domain = no_domain
4585  end if
4586 
4587  if(is_no_domain) then
4588  if(PRESENT(domain)) &
4589  call mpp_error(fatal, 'fms_io(setup_one_field): no_domain cannot be .true. when optional argument domain is present.')
4590  else if(PRESENT(domain))then
4591  d_ptr => domain
4592  else if (ASSOCIATED(current_domain)) then
4593  d_ptr => current_domain
4594  endif
4595 
4596  !--- remove .nc from file name
4597  length = len_trim(filename)
4598  if(filename(length-2:length) == '.nc') then
4599  filename2 = filename(1:length-3)
4600  else
4601  filename2 = filename(1:length)
4602  end if
4603 
4604  !Append a string to the file name
4605  append_string=''
4606  !If the filename_appendix is set override the passed argument.
4607  if(len_trim(filename_appendix) > 0) append_string = filename_appendix
4608 
4609  if(len_trim(append_string) > 0) filename2 = trim(filename2)//'.'//trim(append_string)
4610 
4611  !JWD: This is likely a temporary fix. Since fms_io needs to know tile_count,
4612  !JWD: I just don't see how the physics can remain "tile neutral"
4613  !z1l: one solution is add one more public interface called set_tile_count
4614  call get_mosaic_tile_file(filename2, fname, is_no_domain, domain, tile_count)
4615 
4616  if(Associated(fileobj%var) ) then
4617  ! make sure the consistency of file name
4618  if(trim(fileobj%name) .NE. trim(fname)) call mpp_error(fatal, 'fms_io(setup_one_field): filename = '// &
4619  trim(fname)//' is not consistent with the filename of the restart object = '//trim(fileobj%name) )
4620  else
4621  allocate(fileobj%var(max_fields) )
4622  allocate(fileobj%p0dr(max_time_level_register, max_fields))
4623  allocate(fileobj%p1dr(max_time_level_register, max_fields))
4624  allocate(fileobj%p2dr(max_time_level_register, max_fields))
4625  allocate(fileobj%p3dr(max_time_level_register, max_fields))
4626  allocate(fileobj%p2dr8(max_time_level_register, max_fields))
4627  allocate(fileobj%p3dr8(max_time_level_register, max_fields))
4628  allocate(fileobj%p4dr(max_time_level_register, max_fields))
4629  allocate(fileobj%p0di(max_time_level_register, max_fields))
4630  allocate(fileobj%p1di(max_time_level_register, max_fields))
4631  allocate(fileobj%p2di(max_time_level_register, max_fields))
4632  allocate(fileobj%p3di(max_time_level_register, max_fields))
4633  !--- make sure fname is not used in other restart_file_type object.
4634  do i = 1, num_registered_files
4635  if(trim(fname) == trim(registered_file(i)) ) then
4636  call mpp_error(note, &
4637  'fms_io(setup_one_field): '//trim(fname)//' is already registered with other restart_file_type data')
4638  exit
4639  endif
4640  end do
4642  if( num_registered_files > max_files_w ) call mpp_error(warning, &
4643  'fms_io(setup_one_field): num_registered_files > max_files_w, increase fms_io_nml max_files_w')
4644  registered_file(num_registered_files) = trim(fname)
4645  fileobj%register_id = num_registered_files
4646  fileobj%name = trim(fname)
4647  fileobj%tile_count=1
4648  if(present(tile_count)) fileobj%tile_count = tile_count
4649  if(ASSOCIATED(d_ptr))then
4650  fileobj%is_root_pe = mpp_domain_is_tile_root_pe(d_ptr)
4651  else
4652  fileobj%is_root_pe = mpp_pe() == mpp_root_pe()
4653  endif
4654  fileobj%max_ntime = field_siz(4)
4655  fileobj%nvar = 0
4656  !-- allocate memory
4657  do i = 1, max_fields
4658  fileobj%var(i)%name = 'none'
4659  fileobj%var(i)%domain_present = .false.
4660  fileobj%var(i)%domain_idx = -1
4661  fileobj%var(i)%is_dimvar = .false.
4662  fileobj%var(i)%position = center
4663  fileobj%var(i)%siz(:) = 0
4664  fileobj%var(i)%gsiz(:) = 0
4665  fileobj%var(i)%id_axes(:) = -1
4666  fileobj%var(i)%longname = '';
4667  fileobj%var(i)%units = 'none';
4668  fileobj%var(i)%mandatory = .true.
4669  fileobj%var(i)%initialized = .false.
4670  fileobj%var(i)%compressed_axis = ''
4671  fileobj%var(i)%read_only = .false.
4672  fileobj%var(i)%owns_data = .false.
4673  end do
4674  endif
4675 
4676  ! check if the field is new or not and get position and dimension of the field
4677  index_field = -1
4678  do i = 1, fileobj%nvar
4679  if(trim(fileobj%var(i)%name) == trim(fieldname)) then
4680  index_field = i
4681  exit
4682  end if
4683  end do
4684 
4685  if(index_field > 0) then
4686  cur_var => fileobj%var(index_field)
4687  if(cur_var%siz(1) .NE. field_siz(1) .OR. cur_var%siz(2) .NE. field_siz(2) .OR. cur_var%siz(3) .NE. field_siz(3) ) &
4688  call mpp_error(fatal, 'fms_io(setup_one_field): field size mismatch for field '// &
4689  trim(fieldname)//' of file '//trim(filename) )
4690 
4691  cur_var%siz(4) = cur_var%siz(4) + field_siz(4)
4692  if(fileobj%max_ntime < cur_var%siz(4) ) fileobj%max_ntime = cur_var%siz(4)
4693  ! the time level should be no larger than MAX_TIME_LEVEL_REGISTER ( = 2)
4694  if( cur_var%siz(4) > max_time_level_register ) call mpp_error(fatal, 'fms_io(setup_one_field): ' // &
4695  'the time level of field '//trim(cur_var%name)//' in file '//trim(fileobj%name)// &
4696  ' is greater than MAX_TIME_LEVEL_REGISTER(=2), increase MAX_TIME_LEVEL_REGISTER or check your code')
4697  else
4698  fileobj%nvar = fileobj%nvar +1
4699  if(fileobj%nvar>max_fields) then
4700  write(error_msg,'(I3,"/",I3)') fileobj%nvar, max_fields
4701  call mpp_error(fatal,'fms_io(setup_one_field): max_fields exceeded, needs increasing, nvar/max_fields=' &
4702  //trim(error_msg))
4703  endif
4704  index_field = fileobj%nvar
4705  cur_var => fileobj%var(index_field)
4706  n_field_siz = size(field_siz(:))
4707  cur_var%siz(1:n_field_siz) = field_siz(1:n_field_siz)
4708  cur_var%gsiz(3) = field_siz(3)
4709  if(n_field_siz == 5) cur_var%gsiz(4) = field_siz(5)
4710  cur_var%name = fieldname
4711  cur_var%default_data = default_data
4712  if(present(mandatory)) cur_var%mandatory = mandatory
4713  if(present(read_only)) cur_var%read_only = read_only
4714  if(present(owns_data)) cur_var%owns_data = owns_data
4715  if(present(longname)) then
4716  cur_var%longname = longname
4717  else
4718  cur_var%longname = fieldname
4719  end if
4720  if(present(units)) cur_var%units = units
4721  if(present(position)) cur_var%position = position
4722  if(present(compressed_axis)) cur_var%compressed_axis = compressed_axis
4723  cur_var%is = 1; cur_var%ie = cur_var%siz(1)
4724  cur_var%js = 1; cur_var%je = cur_var%siz(2)
4725 
4726  if(ASSOCIATED(d_ptr) .AND. .NOT. is_scalar_or_1d ) then
4727  cur_var%domain_present = .true.
4728  domain_idx = lookup_domain(d_ptr)
4729  if(domain_idx == -1) then
4730  num_domains = num_domains + 1
4731  if(num_domains > max_domains) call mpp_error(fatal,'fms_io(setup_one_field), 1: max_domains exceeded,' &
4732  //' needs increasing')
4733  domain_idx = num_domains
4734  array_domain(domain_idx) = d_ptr
4735  call mpp_get_domain_components(array_domain(domain_idx), domain_x(domain_idx), domain_y(domain_idx), &
4736  tile_count=tile_count)
4737  endif
4738  cur_var%domain_idx = domain_idx
4739  call mpp_get_domain_shift ( array_domain(domain_idx), ishift, jshift, position)
4740  call mpp_get_global_domain(array_domain(domain_idx), xsize=gxsize,ysize=gysize,tile_count=tile_count)
4741  call mpp_get_compute_domain(array_domain(domain_idx), xsize = cxsize, ysize = cysize, tile_count=tile_count)
4742  call mpp_get_data_domain (array_domain(domain_idx), xsize = dxsize, ysize = dysize, tile_count=tile_count)
4743  if (ishift .NE. 0) then
4744  cxsize = cxsize+ishift; dxsize = dxsize+ishift; gxsize = gxsize + ishift
4745  end if
4746  if (jshift .NE. 0) then
4747  cysize = cysize+jshift; dysize = dysize+jshift; gysize = gysize + jshift
4748  endif
4749  if( (cur_var%siz(1) .NE. cxsize .AND. cur_var%siz(1) .NE. dxsize ) .OR. &
4750  (cur_var%siz(2) .NE. cysize .AND. cur_var%siz(2) .NE. dysize ) ) then
4751  call mpp_error(fatal, 'fms_io(setup_one_field): data should be on either compute domain '//&
4752  'or data domain when domain is present for field '//trim(fieldname)//' of file '//trim(filename) )
4753  end if
4754  cur_var%is = 1 + (cur_var%siz(1) - cxsize)/2
4755  cur_var%ie = cur_var%is + cxsize - 1;
4756  cur_var%js = 1 + (cur_var%siz(2) - cysize)/2
4757  cur_var%je = cur_var%js + cysize - 1;
4758  cur_var%gsiz(1) = gxsize
4759  cur_var%gsiz(2) = gysize
4760  else
4761  cur_var%domain_present=.false.
4762  cur_var%gsiz(1:2) = field_siz(1:2)
4763  endif
4764  end if
4765 
4766  d_ptr =>null()
4767  cur_var =>null()
4768 
4769 end subroutine setup_one_field
4770 
4771 !.....................................................................
4772 subroutine write_data_4d_new(filename, fieldname, data, domain, &
4773  no_domain, position,tile_count, data_default)
4775  character(len=*), intent(in) :: filename, fieldname
4776  real, dimension(:,:,:,:), intent(in) :: data
4777  real, dimension(size(data,1),size(data,2),size(data,3)*size(data,4)) :: data_3d
4778  real, intent(in), optional :: data_default
4779  type(domain2d), intent(in), optional :: domain
4780  logical, intent(in), optional :: no_domain
4781  integer, intent(in), optional :: position, tile_count
4782  integer :: i, k, l
4783 
4784  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(write_data_4d_new):need to call fms_io_init first')
4785  i = 0
4786  do l = 1, size(data,4) ; do k = 1, size(data,3)
4787  i = i + 1
4788  data_3d(:,:,i) = data(:,:,k,l)
4789  enddo ; enddo
4790 
4791  call write_data_3d_new(filename, fieldname, data_3d, domain, &
4792  no_domain, .false., position, tile_count, data_default)
4793 
4794 end subroutine write_data_4d_new
4795 
4796 !.....................................................................
4797 subroutine write_data_2d_new(filename, fieldname, data, domain, &
4798  no_domain, position,tile_count, data_default)
4800  character(len=*), intent(in) :: filename, fieldname
4801  real, dimension(:,:), intent(in) :: data
4802  real, dimension(size(data,1),size(data,2),1) :: data_3d
4803  real, intent(in), optional :: data_default
4804  type(domain2d), intent(in), optional :: domain
4805  logical, intent(in), optional :: no_domain
4806  integer, intent(in), optional :: position, tile_count
4807 
4808  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(write_data_2d_new):need to call fms_io_init first')
4809  data_3d(:,:,1) = data(:,:)
4810 
4811  call write_data_3d_new(filename, fieldname, data_3d, domain, &
4812  no_domain, .false., position, tile_count, data_default)
4813 
4814 end subroutine write_data_2d_new
4815 
4816 ! ........................................................
4817 subroutine write_data_1d_new(filename, fieldname, data,domain, &
4818  no_domain, tile_count, data_default)
4820  type(domain2d), intent(in), optional :: domain
4821  character(len=*), intent(in) :: filename, fieldname
4822  real, dimension(:), intent(in) :: data
4823  real, dimension(size(data(:)),1,1) :: data_3d
4824  real, intent(in), optional :: data_default
4825  logical, intent(in), optional :: no_domain
4826  integer, intent(in), optional :: tile_count
4827 
4828  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(write_data_1d_new): module not initialized')
4829  data_3d(:,1,1) = data(:)
4830  call write_data_3d_new(filename, fieldname, data_3d,domain, &
4831  no_domain=no_domain, scalar_or_1d=.true., tile_count=tile_count, data_default=data_default)
4832 end subroutine write_data_1d_new
4833 
4834 ! ..........................................................
4835 subroutine write_data_scalar_new(filename, fieldname, data, domain, &
4836  no_domain, tile_count, data_default)
4838  type(domain2d), intent(in), optional :: domain
4839  character(len=*), intent(in) :: filename, fieldname
4840  real, intent(in) :: data
4841  real, dimension(1,1,1) :: data_3d
4842  real, intent(in), optional :: data_default
4843  logical, intent(in), optional :: no_domain
4844  integer, intent(in), optional :: tile_count
4845 
4846  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(write_data_scalar_new): module not initialized: '//fieldname)
4847 
4848  data_3d(1,1,1) = data
4849  call write_data_3d_new(filename, fieldname, data_3d,domain, &
4850  no_domain=no_domain, scalar_or_1d=.true., tile_count=tile_count, data_default=data_default)
4851 end subroutine write_data_scalar_new
4852 
4853 ! ..........................................................
4854 
4855 function lookup_field_r(nfile,fieldname)
4856 ! Given fieldname, this function returns the field position in the model's fields list
4857 
4858  integer, intent(in) :: nfile
4859  character(len=*), intent(in) :: fieldname
4860  integer :: lookup_field_r
4861  integer :: j
4862 
4863  lookup_field_r=-1
4864  do j = 1, files_read(nfile)%nvar
4865  if (trim(files_read(nfile)%var(j)%name) == trim(fieldname)) then
4866  lookup_field_r = j
4867  exit
4868  endif
4869  enddo
4870  return
4871 end function lookup_field_r
4872 
4873 
4874 !..........................................................
4875 
4876 function lookup_domain(domain)
4877 ! given domain, this function returns the position of domain in array_domain or -1 if not found
4878 
4879  type(domain2d), intent(in) :: domain
4880  integer :: i, lookup_domain
4881  lookup_domain = -1
4882  do i =1, num_domains
4883  if(domain .EQ. array_domain(i)) then
4884  lookup_domain = i
4885  exit
4886  endif
4887  enddo
4888 end function lookup_domain
4889 !.........................................................
4890 function lookup_axis(axis_sizes,siz,domains,dom)
4892 ! Given axis size (global), this function returns the axis id
4893 
4894  integer, intent(in) :: axis_sizes(:), siz
4895  type(domain1d), optional :: domains(:)
4896  type(domain1d), optional :: dom
4897  integer :: lookup_axis
4898  integer :: j
4899 
4900 
4901  lookup_axis=-1
4902  do j=1,size(axis_sizes(:))
4903  if (siz == axis_sizes(j)) then
4904  if (PRESENT(domains)) then
4905  if (dom .EQ. domains(j)) then
4906  lookup_axis = j
4907  exit
4908  endif
4909  else
4910  lookup_axis = j
4911  exit
4912  endif
4913  endif
4914  enddo
4915  if (lookup_axis == -1) call mpp_error(fatal,'fms_io(lookup_axis): could not find axis in set of axes')
4916 end function lookup_axis
4917 !.....................................................................
4918 ! <SUBROUTINE NAME="field_size">
4919 !<DESCRIPTION>
4920 ! Given filename and fieldname, this subroutine returns the size of field
4921 !</DESCRIPTION>
4922 ! <TEMPLATE>
4923 ! call field_size(filename, fieldname, siz)
4924 ! </TEMPLATE>
4925 ! <IN NAME="filename" TYPE="character" DIM="(*)">
4926 ! File name
4927 ! </IN>
4928 ! <IN NAME="fieldname" TYPE="character" DIM="(*)">
4929 ! Field name
4930 ! </IN>
4931 ! <OUT NAME="siz" TYPE="integer" DIM="(*)">
4932 ! siz must be a dimension(4) array to retrieve the size of the field
4933 ! </OUT>
4934 ! <OUT NAME="field_found" TYPE="logical, optional">
4935 ! if this flag is present, field_size will not abort if
4936 ! called for a non-existent field.
4937 ! Instead it will return T or F depending on
4938 ! whether or not the field was found.
4939 ! </OUT>
4940 subroutine field_size(filename, fieldname, siz, field_found, domain, no_domain )
4942  character(len=*), intent(in) :: filename, fieldname
4943  integer, intent(inout) :: siz(:)
4944  logical, intent(out), optional :: field_found
4945  type(domain2d), intent(in), optional, target :: domain
4946  logical, intent(in), optional :: no_domain
4947 
4948  integer :: nfile, unit
4949  logical :: found, found_file
4950  character(len=256) :: actual_file
4951  logical :: read_dist, io_domain_exist, is_no_domain
4952 
4953  if (size(siz(:)) < 4) call mpp_error(fatal,'fms_io(field_size): size array must be >=4 to receive field size of ' &
4954  //trim(fieldname)//' in file '// trim(filename))
4955 
4956  is_no_domain = .false.
4957  if(present(no_domain)) is_no_domain = no_domain
4958 
4959 !--- first need to get the filename, when is_no_domain is true, only check file without tile
4960 !--- if is_no_domain is false, first check no_domain=.false., then check no_domain = .true.
4961  found_file = get_file_name(filename, actual_file, read_dist, io_domain_exist, no_domain=is_no_domain, &
4962  domain=domain)
4963  !--- when is_no_domain is true and file is not found, send out error message.
4964  if(is_no_domain .AND. .NOT. found_file) call mpp_error(fatal, &
4965  'fms_io_mod(field_size): file '//trim(filename)//' and corresponding distributed file are not found')
4966  found = .false.
4967  if(found_file) then
4968  call get_file_unit(actual_file, unit, nfile, read_dist, io_domain_exist, domain=domain)
4969  call get_size(unit,fieldname,siz,found)
4970  endif
4971 
4972  if(.not.found .AND. .not. is_no_domain) then
4973  found_file = get_file_name(filename, actual_file, read_dist, io_domain_exist, no_domain=.true.)
4974  if(found_file) then
4975  call get_file_unit(actual_file, unit, nfile, read_dist, io_domain_exist, domain=domain)
4976  call get_size(unit,fieldname,siz,found)
4977  endif
4978  endif
4979 
4980 ! If field_found is present we assume that it is being checked on exit.
4981 ! If not present and the field was not found, exit with a FATAL error.
4982  if( PRESENT(field_found) )then
4983  field_found = found
4984  else if (.not. found )then
4985  call mpp_error(fatal, 'fms_io(field_size): field '//trim(fieldname)//' NOT found in file '//trim(actual_file))
4986  end if
4987 
4988  return
4989 end subroutine field_size
4990 ! </SUBROUTINE>
4991 subroutine file_unit(filename, found_file, unit, domain, no_domain)
4993  character(len=*), intent(in) :: filename
4994  logical, intent(out) :: found_file
4995  integer, intent(out) :: unit
4996  type(domain2d), intent(in), optional, target :: domain
4997  logical, intent(in), optional :: no_domain
4998 
4999  integer :: nfile
5000  character(len=256) :: actual_file
5001  logical :: read_dist, io_domain_exist, is_no_domain
5002 
5003 
5004  is_no_domain = .false.
5005  if(present(no_domain)) is_no_domain = no_domain
5006 
5007 !--- first need to get the filename, when is_no_domain is true, only check file without tile
5008 !--- if is_no_domain is false, first check no_domain=.false., then check no_domain = .true.
5009  found_file = get_file_name(filename, actual_file, read_dist, io_domain_exist, no_domain=is_no_domain, &
5010  domain=domain)
5011 
5012  !--- when is_no_domain is true and file is not found, send out error message.
5013  if(is_no_domain .AND. .NOT. found_file) call mpp_error(fatal, &
5014  'fms_io_mod(field_size): file '//trim(filename)//' and corresponding distributed file are not found')
5015 
5016  if(found_file) then
5017  call get_file_unit(actual_file, unit, nfile, read_dist, io_domain_exist, domain=domain)
5018  else if(.not. is_no_domain) then
5019  found_file = get_file_name(filename, actual_file, read_dist, io_domain_exist, no_domain=.true.)
5020  if(found_file) then
5021  call get_file_unit(actual_file, unit, nfile, read_dist, io_domain_exist, domain=domain)
5022  endif
5023  endif
5024 
5025 
5026  return
5027 end subroutine file_unit
5028 
5029 !.....................................................................
5030 ! <SUBROUTINE NAME="dimension_size">
5031 !<DESCRIPTION>
5032 ! Given filename and dimension name, this function returns the size of field
5033 !</DESCRIPTION>
5034 ! <TEMPLATE>
5035 ! dimsize = dimension_size(filename, dimensionname)
5036 ! </TEMPLATE>
5037 ! <IN NAME="filename" TYPE="character" DIM="(*)">
5038 ! File name
5039 ! </IN>
5040 ! <IN NAME="dimensionname" TYPE="character" DIM="(*)">
5041 ! Field name
5042 ! </IN>
5043 function dimension_size(filename, dimname, domain, no_domain )
5045  character(len=*), intent(in) :: filename, dimname
5046  type(domain2d), intent(in), optional, target :: domain
5047  logical, intent(in), optional :: no_domain
5048  integer :: dimension_size
5049 
5050  integer :: nfile, unit
5051  logical :: found, found_file
5052  character(len=256) :: actual_file
5053  logical :: read_dist, io_domain_exist, is_no_domain
5054 
5055  is_no_domain = .false.
5056  if(present(no_domain)) is_no_domain = no_domain
5057 
5058 !--- first need to get the filename, when is_no_domain is true, only check file without tile
5059 !--- if is_no_domain is false, first check no_domain=.false., then check no_domain = .true.
5060  found_file = get_file_name(filename, actual_file, read_dist, io_domain_exist, no_domain=is_no_domain, &
5061  domain=domain)
5062  !--- when is_no_domain is true and file is not found, send out error message.
5063  if(is_no_domain .AND. .NOT. found_file) call mpp_error(fatal, &
5064  'fms_io_mod(dimesion_size): file '//trim(filename)//' and corresponding distributed file are not found')
5065  found = .false.
5066  if(found_file) then
5067  call get_file_unit(actual_file, unit, nfile, read_dist, io_domain_exist, domain=domain)
5068  dimension_size = mpp_get_dimension_length(unit, dimname, found)
5069  endif
5070 
5071  if(.not.found .AND. .not. is_no_domain) then
5072  found_file = get_file_name(filename, actual_file, read_dist, io_domain_exist, no_domain=.true.)
5073  if(found_file) then
5074  call get_file_unit(actual_file, unit, nfile, read_dist, io_domain_exist, domain=domain)
5075  dimension_size = mpp_get_dimension_length(unit, dimname, found)
5076  endif
5077  endif
5078 
5079  if(.not. found) call mpp_error(fatal, &
5080  'fms_io_mod(dimesion_size): failed at inquiring size of dimesion '//trim(dimname)//' from file '//trim(filename))
5081 
5082  return
5083 end function dimension_size
5084 ! </SUBROUTINE>
5085 
5086 
5087 !.....................................................................
5088 ! <SUBROUTINE NAME="get_field_size">
5089 !<DESCRIPTION>
5090 ! Given filename and fieldname, this subroutine returns the size of field
5091 ! This is the io subset interface to field_size
5092 !</DESCRIPTION>
5093 ! <TEMPLATE>
5094 ! call field_size(filename, fieldname, siz)
5095 ! </TEMPLATE>
5096 ! <IN NAME="filename" TYPE="character" DIM="(*)">
5097 ! File name
5098 ! </IN>
5099 ! <IN NAME="fieldname" TYPE="character" DIM="(*)">
5100 ! Field name
5101 ! </IN>
5102 ! <OUT NAME="siz" TYPE="integer" DIM="(*)">
5103 ! siz must be a dimension(4) array to retrieve the size of the field
5104 ! </OUT>
5105 ! <OUT NAME="field_found" TYPE="logical, optional">
5106 ! if this flag is present, field_size will not abort if
5107 ! called for a non-existent field.
5108 ! Instead it will return T or F depending on
5109 ! whether or not the field was found.
5110 ! </OUT>
5111 subroutine get_field_size(filename, fieldname, siz, field_found, domain, no_domain)
5113  character(len=*), intent(in) :: filename, fieldname
5114  integer, intent(inout) :: siz(:)
5115  logical, intent(out), optional :: field_found
5116  type(domain2d), intent(in), optional, target :: domain
5117  logical, intent(in), optional :: no_domain
5118 
5119  integer :: npes, p, unit
5120  integer, allocatable :: pelist(:)
5121  logical :: found, found_file
5122  type(domain2d), pointer :: domain_in =>null()
5123  type(domain2d), pointer :: io_domain =>null()
5124 
5125 
5126  if(PRESENT(domain)) then
5127  domain_in =>domain
5128  elseif(ASSOCIATED(current_domain)) then
5129  domain_in =>current_domain
5130  else
5131  call mpp_error(fatal,'fms_io(get_field_size): The domain must be defined')
5132  endif
5133 
5134  io_domain =>mpp_get_io_domain(domain)
5135  if(.not. ASSOCIATED(io_domain)) call mpp_error(fatal,'fms_io(get_field_size): The io domain must be defined')
5136 
5137  npes = mpp_get_domain_npes(io_domain)
5138  allocate(pelist(npes))
5139  call mpp_get_pelist(io_domain,pelist)
5140 
5141  call file_unit(filename, found_file, unit, domain, no_domain)
5142 
5143  if(mpp_pe() == pelist(1)) then
5144  found=.false.
5145  if(found_file) call get_size(unit,fieldname,siz,found)
5146  if(.not. found) siz(:) = -1
5147  endif
5148  !--- z1l replace mpp_broadcast with mpp_send/mpp_recv to avoid hang in calling MPI_COMM_CREATE
5149  !--- because size(pelist) might be different for different rank.
5150  !--- prepost receive
5151  if( mpp_pe() == pelist(1) ) then
5152  do p = 2, npes
5153  call mpp_send(siz(1), plen=size(siz(:)), to_pe=pelist(p), tag=comm_tag_1)
5154  enddo
5155  call mpp_sync_self()
5156  else
5157  call mpp_recv(siz(1), glen=size(siz(:)), from_pe=pelist(1), block=.false., tag=comm_tag_1)
5158  call mpp_sync_self(check=event_recv)
5159  endif
5160 
5161  found = .true.
5162  if(siz(1) == -1) found=.false.
5163 
5164 ! If field_found is present we assume that it is being checked on exit.
5165 ! If not present and the field was not found, exit with a FATAL error.
5166  if( PRESENT(field_found) )then
5167  field_found = found
5168  else if (.not. found )then
5169  call mpp_error(fatal, 'fms_io(field_size): field '//trim(fieldname)//' NOT found in file '//trim(filename))
5170  endif
5171 end subroutine get_field_size
5172 ! </SUBROUTINE>
5173 
5174 subroutine get_size(unit, fieldname, siz, found)
5175 integer, intent(in) :: unit
5176 character(len=*), intent(in) :: fieldname
5177 integer, intent(inout) :: siz(:)
5178 logical, intent(out) :: found
5179 
5180  character(len=128) :: name
5181  character(len=1) :: cart
5182  integer :: i, ndim, nvar, natt, ntime, siz_in(4), j, len
5183  type(fieldtype) :: fields(max_fields)
5184  type(axistype) :: axes(max_fields)
5185  found = .false.
5186  call mpp_get_info(unit,ndim,nvar,natt,ntime)
5187  if (nvar > max_fields) then
5188  write(error_msg,'(I3,"/",I3)') nvar,max_fields
5189  call mpp_error(fatal,'fms_io(field_size): max_fields too small, needs increasing, nvar/max_fields=' &
5190  //trim(error_msg))!//' in file '//trim(filename))
5191  endif
5192  call mpp_get_fields(unit,fields(1:nvar))
5193  do i=1, nvar
5194  call mpp_get_atts(fields(i),name=name)
5195  if (lowercase(trim(name)) == lowercase(trim(fieldname))) then
5196  call mpp_get_atts(fields(i),ndim=ndim)
5197  call mpp_get_atts(fields(i),axes=axes(1:ndim))
5198  call mpp_get_atts(fields(i),siz=siz_in)
5199  siz = siz_in
5200  siz(4) = ntime
5201  if(ndim == 1) then
5202  call mpp_get_atts(axes(1), len=siz(1))
5203  end if
5204  do j = 1, ndim
5205  call mpp_get_atts(axes(j),len=len)
5206  call get_axis_cart(axes(j),cart)
5207  select case (cart)
5208  case ('X')
5209  siz(1) = len
5210  case('Y')
5211  siz(2) = len
5212  case('Z')
5213  siz(3) = len
5214  case('T')
5215  siz(4) = len
5216  end select
5217  enddo
5218  found = .true.
5219  exit
5220  endif
5221  enddo
5222 
5223  if(.not. found) then
5224  call mpp_get_axes(unit,axes(1:ndim))
5225  do i=1, ndim
5226  call mpp_get_atts(axes(i),name=name, len= siz_in(1))
5227  if (lowercase(trim(name)) == lowercase(trim(fieldname))) then
5228  siz(1)= siz_in(1)
5229  found = .true.
5230  exit
5231  endif
5232  enddo
5233  endif
5234 end subroutine get_size
5235 
5236 ! <SUBROUTINE NAME="read_data">
5237 !<DESCRIPTION>
5238 ! This routine performs reading "fieldname" stored in "filename". The data values of fieldname
5239 ! will be stored in "data" at the end of this routine. For fieldname with multiple timelevel
5240 ! just repeat the routine with explicit timelevel in each call.
5241 !</DESCRIPTION>
5242 ! <TEMPLATE>
5243 ! call read_data(filename,fieldname,data,domain,timelevel)
5244 ! </TEMPLATE>
5245 ! <IN NAME="filename" TYPE="character" DIM="(*)">
5246 ! File name
5247 ! </IN>
5248 ! <IN NAME="fieldname" TYPE="character" DIM="(*)">
5249 ! Field name
5250 ! </IN>
5251 ! <IN NAME="domain" TYPE="domain, optional">
5252 ! domain of fieldname
5253 ! </IN>
5254 ! <IN NAME="timelevel" TYPE="integer, optional">
5255 ! time level of fieldname
5256 ! </IN>
5257 ! <OUT NAME="data" TYPE="real">
5258 ! array containing data of fieldname
5259 ! </OUT>
5260 !=====================================================================================
5261 subroutine read_data_i3d_new(filename,fieldname,data,domain,timelevel, &
5262  no_domain,position, tile_count)
5263  character(len=*), intent(in) :: filename, fieldname
5264  integer, dimension(:,:,:), intent(inout) :: data ! 3 dimensional data
5265  type(domain2d), intent(in), optional :: domain
5266  integer, intent(in), optional :: timelevel
5267  logical, intent(in), optional :: no_domain
5268  integer, intent(in) , optional :: position, tile_count
5269 
5270  real, dimension(size(data,1),size(data,2),size(data,3)) :: r_data
5271  r_data = 0
5272  call read_data_3d_new(filename,fieldname,r_data,domain,timelevel, &
5273  no_domain, .false., position, tile_count)
5274  data = ceiling(r_data)
5275 end subroutine read_data_i3d_new
5276 
5277 subroutine read_data_i2d_new(filename,fieldname,data,domain,timelevel, &
5278  no_domain,position, tile_count)
5279  character(len=*), intent(in) :: filename, fieldname
5280  integer, dimension(:,:), intent(inout) :: data ! 2 dimensional data
5281  type(domain2d), intent(in), optional :: domain
5282  integer, intent(in), optional :: timelevel
5283  logical, intent(in), optional :: no_domain
5284  integer, intent(in) , optional :: position, tile_count
5285  real, dimension(size(data,1),size(data,2)) :: r_data
5286 
5287  r_data = 0
5288  call read_data_2d_new(filename,fieldname,r_data,domain,timelevel, &
5289  no_domain, position, tile_count)
5290  data = ceiling(r_data)
5291 end subroutine read_data_i2d_new
5292 !.....................................................................
5293 subroutine read_data_i1d_new(filename,fieldname,data,domain,timelevel, &
5294  no_domain, tile_count)
5295  character(len=*), intent(in) :: filename, fieldname
5296  integer, dimension(:), intent(inout) :: data ! 1 dimensional data
5297  type(domain2d), intent(in), optional :: domain
5298  integer, intent(in) , optional :: timelevel
5299  logical, intent(in), optional :: no_domain
5300  integer, intent(in), optional :: tile_count
5301 
5302  real, dimension(size(data,1)) :: r_data
5303 
5304  call read_data_1d_new(filename,fieldname,r_data,domain,timelevel, &
5305  no_domain, tile_count)
5306  data = ceiling(r_data)
5307 end subroutine read_data_i1d_new
5308 !.....................................................................
5309 subroutine read_data_iscalar_new(filename,fieldname,data,domain,timelevel, &
5310  no_domain, tile_count)
5311  character(len=*), intent(in) :: filename, fieldname
5312  integer, intent(inout) :: data
5313  type(domain2d), intent(in), optional :: domain
5314  integer, intent(in) , optional :: timelevel
5315  logical, intent(in), optional :: no_domain
5316  integer, intent(in), optional :: tile_count
5317 
5318  real :: r_data
5319  call read_data_scalar_new(filename,fieldname,r_data,domain,timelevel, &
5320  no_domain, tile_count)
5321  data = ceiling(r_data)
5322 end subroutine read_data_iscalar_new
5323 !=====================================================================================
5324 subroutine read_data_3d_new(filename,fieldname,data,domain,timelevel, &
5325  no_domain, scalar_or_1d, position, tile_count)
5326  character(len=*), intent(in) :: filename, fieldname
5327  real, dimension(:,:,:), intent(inout) :: data ! 3 dimensional data
5328  type(domain2d), target, optional, intent(in) :: domain
5329  integer, optional, intent(in) :: timelevel
5330  logical, optional, intent(in) :: no_domain
5331  logical, optional, intent(in) :: scalar_or_1d
5332  integer, optional, intent(in) :: position, tile_count
5333 
5334  character(len=256) :: fname
5335  integer :: unit, siz_in(4)
5336  integer :: file_index ! index of the opened file in array files
5337  integer :: tlev=1
5338  integer :: index_field ! position of the fieldname in the list of variables
5339  integer :: cxsize, cysize
5340  integer :: dxsize, dysize
5341  integer :: gxsize, gysize
5342  integer :: ishift, jshift
5343  logical :: is_scalar_or_1d = .false.
5344  logical :: is_no_domain = .false.
5345  logical :: read_dist, io_domain_exist, found_file
5346  type(domain2d), pointer, save :: d_ptr =>null()
5347  type(domain2d), pointer, save :: io_domain =>null()
5348 
5349 
5350 ! read disttributed files is used when reading restart files that are NOT mppnccombined. In this
5351 ! case PE 0 will read file_res.nc.0000, PE 1 will read file_res.nc.0001 and so forth.
5352 !
5353 ! Initialize files to default values
5354  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_data_3d_new): module not initialized')
5355  is_no_domain = .false.
5356  if (PRESENT(no_domain)) THEN
5357  if(PRESENT(domain) .AND. no_domain) &
5358  call mpp_error(fatal, 'fms_io(read_data_3d_new): no_domain cannot be .true. when optional argument domain is present.')
5359  is_no_domain = no_domain
5360  endif
5361 
5362  if(PRESENT(domain))then
5363  d_ptr => domain
5364  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
5365  d_ptr => current_domain
5366  endif
5367 
5368  is_scalar_or_1d = .false.
5369  if(present(scalar_or_1d)) is_scalar_or_1d = scalar_or_1d
5370 
5371  if(.not. PRESENT(domain) .and. .not. ASSOCIATED(current_domain) ) is_no_domain = .true.
5372 
5373  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, is_no_domain, domain, tile_count)
5374  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_data_3d_new): file ' //trim(filename)// &
5375  '(with the consideration of tile number) and corresponding distributed file are not found')
5376  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=domain)
5377 
5378  siz_in(3) = size(data,3)
5379  if(is_no_domain .or. .NOT. associated(d_ptr) .or. is_scalar_or_1d) then
5380  gxsize = size(data,1)
5381  gysize = size(data,2)
5382  else if(read_dist) then
5383  if(io_domain_exist) then
5384  io_domain=>mpp_get_io_domain(d_ptr)
5385  call mpp_get_global_domain(io_domain, xsize = gxsize, ysize = gysize, tile_count=tile_count, position=position)
5386  io_domain=>null()
5387  else
5388  call mpp_get_compute_domain(d_ptr, xsize = gxsize, ysize = gysize, tile_count=tile_count, position=position)
5389  endif
5390  else
5391  call mpp_get_compute_domain(d_ptr, xsize = cxsize, ysize = cysize, tile_count=tile_count, position=position)
5392  call mpp_get_data_domain (d_ptr, xsize = dxsize, ysize = dysize, tile_count=tile_count, position=position)
5393  call mpp_get_global_domain (d_ptr, xsize = gxsize, ysize = gysize, tile_count=tile_count, position=position)
5394  call mpp_get_domain_shift (d_ptr, ishift, jshift, position)
5395  if( (size(data,1) .NE. cxsize .AND. size(data,1) .NE. dxsize) .OR. &
5396  (size(data,2) .NE. cysize .AND. size(data,2) .NE. dysize) )then
5397  call mpp_error(fatal,'fms_io(read_data_3d_new): data should be on either compute domain '//&
5398  'or data domain when domain is present. '//&
5399  'shape(data)=',shape(data),' cxsize,cysize,dxsize,dysize=',(/cxsize,cysize,dxsize,dysize/))
5400  end if
5401  endif
5402 
5403  if (PRESENT(timelevel)) then
5404  tlev = timelevel
5405  else
5406  tlev = 1
5407  endif
5408 
5409  call get_field_id(unit, file_index, fieldname, index_field, is_no_domain, .false. )
5410  siz_in(1:4) = files_read(file_index)%var(index_field)%siz(1:4)
5411  if(files_read(file_index)%var(index_field)%is_dimvar ) then
5412  if (.not. read_dist) then
5413  if (siz_in(1) /= gxsize) &
5414  call mpp_error(fatal,'fms_io(read_data_3d_new), field '//trim(fieldname)// &
5415  ' in file '//trim(filename)//' field size mismatch 2')
5416  endif
5417  else
5418  if (siz_in(1) /= gxsize .or. siz_in(2) /= gysize .or. siz_in(3) /= size(data,3)) then
5419  print *, gxsize, gysize, size(data, 3), siz_in(1), siz_in(2), siz_in(3)
5420  call mpp_error(fatal,'fms_io(read_data_3d_new), field '//trim(fieldname)// &
5421  ' in file '//trim(filename)//': field size mismatch 1')
5422  endif
5423  end if
5424  if ( tlev < 1 .or. files_read(file_index)%max_ntime < tlev) then
5425  write(error_msg,'(I5,"/",I5)') tlev, files_read(file_index)%max_ntime
5426  call mpp_error(fatal,'fms_io(read_data_3d_new): time level out of range, time level/max_time_level=' &
5427  //trim(error_msg)//' in field/file: '//trim(fieldname)//'/'//trim(filename))
5428  endif
5429 
5430  if(is_no_domain .OR. is_scalar_or_1d) then
5431  if (files_read(file_index)%var(index_field)%is_dimvar) then
5432  call mpp_get_axis_data(files_read(file_index)%var(index_field)%axis,data(:,1,1))
5433  else
5434  call mpp_read(unit,files_read(file_index)%var(index_field)%field,data(:,:,:),tlev)
5435  endif
5436  else
5437  call mpp_read(unit,files_read(file_index)%var(index_field)%field,d_ptr,data,tlev,tile_count)
5438  endif
5439 
5440  d_ptr =>null()
5441 
5442  return
5443 end subroutine read_data_3d_new
5444 
5445 
5446 !=====================================================================================
5447 subroutine read_compressed_i1d(filename,fieldname,data,domain,timelevel,start,nread,threading)
5448  character(len=*), intent(in) :: filename, fieldname
5449  integer, dimension(:), intent(inout) :: data ! 1 dimensional data
5450  type(domain2d), intent(in), optional :: domain
5451  integer, intent(in) , optional :: timelevel
5452  integer, intent(in) , optional :: start(:), nread(:)
5453  integer, intent(in) , optional :: threading
5454  real, dimension(size(data)) :: r_data
5455 
5456  r_data = 0.0
5457  call read_compressed_1d(filename,fieldname,r_data,domain,timelevel,start,nread,threading)
5458  data = ceiling(r_data)
5459 end subroutine read_compressed_i1d
5460 !.....................................................................
5461 subroutine read_compressed_i2d(filename,fieldname,data,domain,timelevel,start,nread,threading)
5462  character(len=*), intent(in) :: filename, fieldname
5463  integer, dimension(:,:), intent(inout) :: data ! 2 dimensional data
5464  type(domain2d), intent(in), optional :: domain
5465  integer, intent(in), optional :: timelevel
5466  integer, intent(in) , optional :: start(:), nread(:)
5467  integer, intent(in) , optional :: threading
5468  real, dimension(size(data,1),size(data,2)) :: r_data
5469 
5470  r_data = 0.0
5471  call read_compressed_2d(filename,fieldname,r_data,domain,timelevel,start,nread,threading)
5472  data = ceiling(r_data)
5473 end subroutine read_compressed_i2d
5474 !.....................................................................
5475 subroutine read_compressed_1d(filename,fieldname,data,domain,timelevel,start,nread,threading)
5476  character(len=*), intent(in) :: filename, fieldname
5477  real, dimension(:), intent(inout) :: data !1 dimensional data
5478  real, dimension(size(data,1),1) :: data_2d
5479  type(domain2d), intent(in), optional :: domain
5480  integer, intent(in) , optional :: timelevel
5481  integer, intent(in) , optional :: start(:), nread(:)
5482  integer, intent(in) , optional :: threading
5483 #ifdef use_CRI_pointers
5484  pointer( p, data_2d )
5485  p = loc(data)
5486 #endif
5487  call read_compressed_2d(filename,fieldname,data_2d,domain,timelevel,start,nread,threading)
5488 end subroutine read_compressed_1d
5489 !.....................................................................
5490 subroutine read_compressed_2d(filename,fieldname,data,domain,timelevel,start,nread,threading)
5491  character(len=*), intent(in) :: filename, fieldname
5492  real, dimension(:,:), intent(inout) :: data !2 dimensional data
5493  type(domain2d), target, optional, intent(in) :: domain
5494  integer, intent(in) , optional :: timelevel
5495  integer, intent(in) , optional :: start(:), nread(:)
5496  integer, intent(in) , optional :: threading
5497 
5498  character(len=256) :: fname
5499  integer :: unit, siz_in(4)
5500  integer :: file_index ! index of the opened file in array files
5501  integer :: index_field ! position of the fieldname in the list of variables
5502  logical :: read_dist, io_domain_exist, found_file
5503  type(domain2d), pointer, save :: d_ptr =>null()
5504  type(domain2d), pointer, save :: io_domain =>null()
5505 
5506 ! Initialize files to default values
5507  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_compressed_2d): module not initialized')
5508 
5509  if(PRESENT(domain))then
5510  d_ptr => domain
5511  elseif (ASSOCIATED(current_domain)) then
5512  d_ptr => current_domain
5513  else
5514  call mpp_error(fatal,'fms_io(read_compressed_2d): Domain must be an argument or set by set_domain()')
5515  endif
5516 
5517  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, domain=d_ptr)
5518  if(.not. found_file) then
5519  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, no_domain=.true. )
5520  endif
5521  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_compressed_2d): file ' //trim(filename)// &
5522  '(with the consideration of tile number) and corresponding distributed file are not found')
5523  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=d_ptr)
5524  call get_field_id(unit, file_index, fieldname, index_field, .false., .false. )
5525 
5526  if (files_read(file_index)%var(index_field)%is_dimvar) then
5527  call mpp_get_axis_data(files_read(file_index)%var(index_field)%axis,data(:,1))
5528  else
5529  call mpp_read_compressed(unit,files_read(file_index)%var(index_field)%field,d_ptr,data,timelevel,start,nread,threading)
5530  endif
5531  d_ptr =>null()
5532 end subroutine read_compressed_2d
5533 
5534 !.....................................................................
5535 subroutine read_compressed_3d(filename,fieldname,data,domain,timelevel)
5536  character(len=*), intent(in) :: filename, fieldname
5537  real, dimension(:,:,:), intent(inout) :: data !3 dimensional data
5538  type(domain2d), target, optional, intent(in) :: domain
5539  integer, intent(in) , optional :: timelevel
5540 
5541  character(len=256) :: fname
5542  integer :: unit
5543  integer :: file_index ! index of the opened file in array files
5544  integer :: index_field ! position of the fieldname in the list of variables
5545  logical :: read_dist, io_domain_exist, found_file
5546  type(domain2d), pointer, save :: d_ptr =>null()
5547  type(domain2d), pointer, save :: io_domain =>null()
5548 
5549 ! Initialize files to default values
5550  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_compressed_3d): module not initialized')
5551 
5552  if(PRESENT(domain))then
5553  d_ptr => domain
5554  elseif (ASSOCIATED(current_domain)) then
5555  d_ptr => current_domain
5556  else
5557  call mpp_error(fatal,'fms_io(read_compressed_3d): Domain must be an argument or set by set_domain()')
5558  endif
5559 
5560  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, domain=d_ptr)
5561  if(.not. found_file) then
5562  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, no_domain=.true. )
5563  endif
5564  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_compressed_3d): file ' //trim(filename)// &
5565  '(with the consideration of tile number) and corresponding distributed file are not found')
5566  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=d_ptr)
5567  call get_field_id(unit, file_index, fieldname, index_field, .false., .false. )
5568 
5569  if (files_read(file_index)%var(index_field)%is_dimvar) then
5570  call mpp_get_axis_data(files_read(file_index)%var(index_field)%axis,data(:,1,1))
5571  else
5572  call mpp_read_compressed(unit,files_read(file_index)%var(index_field)%field,d_ptr,data,timelevel)
5573  endif
5574  d_ptr =>null()
5575 end subroutine read_compressed_3d
5576 
5577 !.....................................................................
5578 subroutine read_distributed_a1d(unit,fmt,iostat,data)
5579  integer, intent(in) :: unit
5580  character(*), intent(in) :: fmt
5581  integer, intent(out) :: iostat
5582  character(len=*), dimension(:), intent(inout) :: data
5583 
5584  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_distributed_a1D): module not initialized')
5585  call mpp_read_distributed_ascii(unit,fmt,dr_set_size,data,iostat)
5586 end subroutine read_distributed_a1d
5587 
5588 !.....................................................................
5589 subroutine read_distributed_i1d(unit,fmt,iostat,data)
5590  integer, intent(in) :: unit
5591  character(*), intent(in) :: fmt
5592  integer, intent(out) :: iostat
5593  integer, dimension(:), intent(inout) :: data
5594 
5595  integer, allocatable :: pelist(:)
5596  integer :: i,lsize
5597  logical :: is_ioroot=.false.
5598 
5599  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_distributed_i1D): module not initialized')
5600  call mpp_read_distributed_ascii(unit,fmt,dr_set_size,data,iostat)
5601 end subroutine read_distributed_i1d
5602 
5603 !.....................................................................
5604 subroutine read_distributed_iscalar(unit,fmt,iostat,data)
5605  integer, intent(in) :: unit
5606  character(*), intent(in) :: fmt
5607  integer, intent(out) :: iostat
5608  integer, intent(inout) :: data
5609 
5610  integer :: idata(1)
5611  pointer(ptr,idata)
5612 
5613  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_distributed_iscalar): module not initialized')
5614  ptr = loc(data)
5615  call read_distributed(unit,fmt,iostat,idata)
5616 end subroutine read_distributed_iscalar
5617 
5618 !.....................................................................
5619 subroutine read_distributed_r3d(unit,fmt,iostat,data)
5620  integer, intent(in) :: unit
5621  character(*), intent(in) :: fmt
5622  integer, intent(out) :: iostat
5623  real, dimension(:,:,:), intent(inout) :: data
5624 
5625  real :: data1D(size(data))
5626  pointer(ptr,data1d)
5627 
5628  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_distributed_r5D): module not initialized')
5629  ptr = loc(data)
5630  call read_distributed(unit,fmt,iostat,data1d)
5631 end subroutine read_distributed_r3d
5632 
5633 !.....................................................................
5634 subroutine read_distributed_r5d(unit,fmt,iostat,data)
5635  integer, intent(in) :: unit
5636  character(*), intent(in) :: fmt
5637  integer, intent(out) :: iostat
5638  real, dimension(:,:,:,:,:), intent(inout) :: data
5639 
5640  real :: data1D(size(data))
5641  pointer(ptr,data1d)
5642 
5643  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_distributed_r5D): module not initialized')
5644  ptr = loc(data)
5645  call read_distributed(unit,fmt,iostat,data1d)
5646 end subroutine read_distributed_r5d
5647 
5648 !.....................................................................
5649 subroutine read_distributed_r1d(unit,fmt,iostat,data)
5650  integer, intent(in) :: unit
5651  character(*), intent(in) :: fmt
5652  integer, intent(out) :: iostat
5653  real, dimension(:), intent(inout) :: data
5654 
5655  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_distributed_r1D): module not initialized')
5656  call mpp_read_distributed_ascii(unit,fmt,dr_set_size,data,iostat)
5657 end subroutine read_distributed_r1d
5658 
5659 !=====================================================================================
5660 subroutine read_data_2d_region(filename,fieldname,data,start,nread,domain, &
5661  no_domain, tile_count)
5662  character(len=*), intent(in) :: filename, fieldname
5663  real, dimension(:,:), intent(inout) :: data ! 3 dimensional data
5664  integer, dimension(:), intent(in) :: start, nread
5665  type(domain2d), target, optional, intent(in) :: domain
5666  logical, optional, intent(in) :: no_domain
5667  integer, optional, intent(in) :: tile_count
5668  character(len=256) :: fname
5669  integer :: unit, siz_in(4)
5670  integer :: file_index ! index of the opened file in array files
5671  integer :: index_field ! position of the fieldname in the list of variables
5672  logical :: is_no_domain = .false.
5673  logical :: read_dist, io_domain_exist, found_file
5674  type(domain2d), pointer, save :: d_ptr =>null()
5675 
5676 
5677 ! Initialize files to default values
5678  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_data_2d_region): module not initialized')
5679  is_no_domain = .false.
5680  if (PRESENT(no_domain)) is_no_domain = no_domain
5681 
5682  if(PRESENT(domain))then
5683  d_ptr => domain
5684  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
5685  d_ptr => current_domain
5686  endif
5687 
5688  if(.not. PRESENT(domain) .and. .not. ASSOCIATED(current_domain) ) is_no_domain = .true.
5689 
5690  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, is_no_domain, domain, tile_count)
5691  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_data_2d_region): file ' //trim(filename)// &
5692  '(with the consideration of tile number) and corresponding distributed file are not found')
5693  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=domain)
5694 
5695 
5696  call get_field_id(unit, file_index, fieldname, index_field, is_no_domain, .false. )
5697  siz_in(1:4) = files_read(file_index)%var(index_field)%siz(1:4)
5698  if(files_read(file_index)%var(index_field)%is_dimvar) then
5699  call mpp_error(fatal, 'fms_io_mod(read_data_2d_region): the field should not be a dimension variable')
5700  endif
5701  call mpp_read(unit,files_read(file_index)%var(index_field)%field,data,start, nread)
5702 
5703  d_ptr =>null()
5704 
5705  return
5706 end subroutine read_data_2d_region
5707 
5708 subroutine read_data_3d_region(filename,fieldname,data,start,nread,domain, &
5709  no_domain, tile_count)
5710  character(len=*), intent(in) :: filename, fieldname
5711  real, dimension(:,:,:), intent(inout) :: data ! 3 dimensional data
5712  integer, dimension(:), intent(in) :: start, nread
5713  type(domain2d), target, optional, intent(in) :: domain
5714  logical, optional, intent(in) :: no_domain
5715  integer, optional, intent(in) :: tile_count
5716  character(len=256) :: fname
5717  integer :: unit, siz_in(4)
5718  integer :: file_index ! index of the opened file in array files
5719  integer :: index_field ! position of the fieldname in the list of variables
5720  logical :: is_no_domain = .false.
5721  logical :: read_dist, io_domain_exist, found_file
5722  type(domain2d), pointer, save :: d_ptr =>null()
5723 
5724 
5725 ! Initialize files to default values
5726  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_data_3d_region): module not initialized')
5727  is_no_domain = .false.
5728  if (PRESENT(no_domain)) is_no_domain = no_domain
5729 
5730  if(PRESENT(domain))then
5731  d_ptr => domain
5732  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
5733  d_ptr => current_domain
5734  endif
5735 
5736  if(.not. PRESENT(domain) .and. .not. ASSOCIATED(current_domain) ) is_no_domain = .true.
5737 
5738  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, is_no_domain, domain, tile_count)
5739  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_data_2d_region): file ' //trim(filename)// &
5740  '(with the consideration of tile number) and corresponding distributed file are not found')
5741  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=domain)
5742 
5743 
5744  call get_field_id(unit, file_index, fieldname, index_field, is_no_domain, .false. )
5745  siz_in(1:4) = files_read(file_index)%var(index_field)%siz(1:4)
5746  if(files_read(file_index)%var(index_field)%is_dimvar) then
5747  call mpp_error(fatal, 'fms_io_mod(read_data_3d_region): the field should not be a dimension variable')
5748  endif
5749  call mpp_read(unit,files_read(file_index)%var(index_field)%field,data,start, nread)
5750 
5751  d_ptr =>null()
5752 
5753  return
5754 end subroutine read_data_3d_region
5755 
5756 #ifdef OVERLOAD_R8
5757 !=====================================================================================
5758 subroutine read_data_2d_region_r8(filename,fieldname,data,start,nread,domain, &
5759  no_domain, tile_count)
5760  character(len=*), intent(in) :: filename, fieldname
5761  real(kind=8), dimension(:,:), intent(inout) :: data ! 3 dimensional data
5762  integer, dimension(:), intent(in) :: start, nread
5763  type(domain2d), target, optional, intent(in) :: domain
5764  logical, optional, intent(in) :: no_domain
5765  integer, optional, intent(in) :: tile_count
5766  character(len=256) :: fname
5767  integer :: unit, siz_in(4)
5768  integer :: file_index ! index of the opened file in array files
5769  integer :: index_field ! position of the fieldname in the list of variables
5770  logical :: is_no_domain = .false.
5771  logical :: read_dist, io_domain_exist, found_file
5772  type(domain2d), pointer, save :: d_ptr =>null()
5773 
5774 
5775 ! Initialize files to default values
5776  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_data_2d_region_r8): module not initialized')
5777  is_no_domain = .false.
5778  if (PRESENT(no_domain)) is_no_domain = no_domain
5779 
5780  if(PRESENT(domain))then
5781  d_ptr => domain
5782  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
5783  d_ptr => current_domain
5784  endif
5785 
5786  if(.not. PRESENT(domain) .and. .not. ASSOCIATED(current_domain) ) is_no_domain = .true.
5787 
5788  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, is_no_domain, domain, tile_count)
5789  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_data_2d_region): file ' //trim(filename)// &
5790  '(with the consideration of tile number) and corresponding distributed file are not found')
5791  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=domain)
5792 
5793 
5794  call get_field_id(unit, file_index, fieldname, index_field, is_no_domain, .false. )
5795  siz_in(1:4) = files_read(file_index)%var(index_field)%siz(1:4)
5796  if(files_read(file_index)%var(index_field)%is_dimvar) then
5797  call mpp_error(fatal, 'fms_io_mod(read_data_2d_region_r8): the field should not be a dimension variable')
5798  endif
5799  call mpp_read(unit,files_read(file_index)%var(index_field)%field,data,start, nread)
5800 
5801  d_ptr =>null()
5802 
5803  return
5804 end subroutine read_data_2d_region_r8
5805 
5806 subroutine read_data_3d_region_r8(filename,fieldname,data,start,nread,domain, &
5807  no_domain, tile_count)
5808  character(len=*), intent(in) :: filename, fieldname
5809  real(kind=8), dimension(:,:,:), intent(inout) :: data ! 3 dimensional data
5810  integer, dimension(:), intent(in) :: start, nread
5811  type(domain2d), target, optional, intent(in) :: domain
5812  logical, optional, intent(in) :: no_domain
5813  integer, optional, intent(in) :: tile_count
5814  character(len=256) :: fname
5815  integer :: unit, siz_in(4)
5816  integer :: file_index ! index of the opened file in array files
5817  integer :: index_field ! position of the fieldname in the list of variables
5818  logical :: is_no_domain = .false.
5819  logical :: read_dist, io_domain_exist, found_file
5820  type(domain2d), pointer, save :: d_ptr =>null()
5821 
5822 
5823 ! Initialize files to default values
5824  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_data_3d_region_r8): module not initialized')
5825  is_no_domain = .false.
5826  if (PRESENT(no_domain)) is_no_domain = no_domain
5827 
5828  if(PRESENT(domain))then
5829  d_ptr => domain
5830  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
5831  d_ptr => current_domain
5832  endif
5833 
5834  if(.not. PRESENT(domain) .and. .not. ASSOCIATED(current_domain) ) is_no_domain = .true.
5835 
5836  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, is_no_domain, domain, tile_count)
5837  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_data_2d_region): file ' //trim(filename)// &
5838  '(with the consideration of tile number) and corresponding distributed file are not found')
5839  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist, domain=domain)
5840 
5841 
5842  call get_field_id(unit, file_index, fieldname, index_field, is_no_domain, .false. )
5843  siz_in(1:4) = files_read(file_index)%var(index_field)%siz(1:4)
5844  if(files_read(file_index)%var(index_field)%is_dimvar) then
5845  call mpp_error(fatal, 'fms_io_mod(read_data_3d_region_r8): the field should not be a dimension variable')
5846  endif
5847  call mpp_read(unit,files_read(file_index)%var(index_field)%field,data,start, nread)
5848 
5849  d_ptr =>null()
5850 
5851  return
5852 end subroutine read_data_3d_region_r8
5853 #endif
5854 
5855 
5856 !=====================================================================================
5857 !--- we assume any text data are at most 2-dimensional and level is for first dimension
5858 subroutine read_data_text(filename,fieldname,data,level)
5859  character(len=*), intent(in) :: filename, fieldname
5860  character(len=*), intent(out) :: data
5861  integer, intent(in) , optional :: level
5862  logical :: file_opened, found_file, read_dist, io_domain_exist
5863  integer :: lev, unit, index_field
5864  integer :: file_index
5865  character(len=256) :: fname
5866 
5867 ! Initialize files to default values
5868  if(.not.module_is_initialized) call mpp_error(fatal,'fms_io(read_data_text): module not initialized')
5869 
5870  file_opened=.false.
5871  if (PRESENT(level)) then
5872  lev = level
5873  else
5874  lev = 1
5875  endif
5876 
5877  found_file = get_file_name(filename, fname, read_dist, io_domain_exist, no_domain=.true. )
5878  if(.not.found_file) call mpp_error(fatal, 'fms_io_mod(read_data_text): file ' //trim(filename)// &
5879  '(with the consideration of tile number) and corresponding distributed file are not found')
5880  call get_file_unit(fname, unit, file_index, read_dist, io_domain_exist )
5881 
5882 ! Get info of this file and field
5883  call get_field_id(unit, file_index, fieldname, index_field, .true., .true. )
5884 
5885  if ( lev < 1 .or. lev > files_read(file_index)%var(index_field)%siz(1) ) then
5886  write(error_msg,'(I5,"/",I5)') lev, files_read(file_index)%var(index_field)%siz(1)
5887  call mpp_error(fatal,'fms_io(read_data_text): text level out of range, level/max_level=' &
5888  //trim(error_msg)//' in field/file: '//trim(fieldname)//'/'//trim(filename))
5889  endif
5890 
5891  call mpp_read(unit,files_read(file_index)%var(index_field)%field,data, level=level)
5892  return
5893 end subroutine read_data_text
5894 !..............................................................
5895 ! </SUBROUTINE>
5896 
5897 subroutine read_data_4d_new(filename,fieldname,data,domain,timelevel,&
5898  no_domain,position,tile_count)
5899  character(len=*), intent(in) :: filename, fieldname
5900  real, dimension(:,:,:,:), intent(inout) :: data !2 dimensional data
5901  real, dimension(size(data,1),size(data,2),size(data,3)*size(data,4)) :: data_3d
5902  type(domain2d), intent(in), optional :: domain
5903  integer, intent(in) , optional :: timelevel
5904  logical, intent(in), optional :: no_domain
5905  integer, intent(in) , optional :: position, tile_count
5906 
5907  integer :: i, k, l
5908  integer :: isc,iec,jsc,jec,isd,ied,jsd,jed
5909  integer :: isg,ieg,jsg,jeg
5910  integer :: xsize_c,ysize_c,xsize_d,ysize_d
5911  integer :: xsize_g,ysize_g, ishift, jshift
5912 
5913 !#ifdef use_CRI_pointers
5914 ! pointer( p, data_3d )
5915 ! p = LOC(data)
5916 !#endif
5917 
5918  call read_data_3d_new(filename,fieldname,data_3d,domain,timelevel,&
5919  no_domain,.false., position,tile_count)
5920 
5921  if(PRESENT(domain)) then
5922  call mpp_get_global_domain( domain,isg,ieg,jsg,jeg,xsize=xsize_g,ysize=ysize_g, tile_count=tile_count, position=position)
5923  call mpp_get_compute_domain( domain,isc,iec,jsc,jec,xsize=xsize_c,ysize=ysize_c, tile_count=tile_count, position=position)
5924  call mpp_get_data_domain( domain,isd,ied,jsd,jed,xsize=xsize_d,ysize=ysize_d, tile_count=tile_count, position=position)
5925  call mpp_get_domain_shift (domain, ishift, jshift, position)
5926  if(((size(data,1)==xsize_c) .and. (size(data,2)==ysize_c))) then !on_comp_domain
5927  i = 0
5928  do l = 1, size(data,4) ; do k = 1, size(data,3)
5929  i = i + 1
5930  data(:,:,k,l) = data_3d(:,:,i)
5931  enddo ; enddo
5932  else if((size(data,1)==xsize_d) .and. (size(data,2)==ysize_d)) then !on_data_domain
5933  i = 0
5934  do l = 1, size(data,4) ; do k = 1, size(data,3)
5935  i = i + 1
5936  data(isc-isd+1:iec-isd+1,jsc-jsd+1:jec-jsd+1,k,l) = data_3d(isc-isd+1:iec-isd+1,jsc-jsd+1:jec-jsd+1,i)
5937  enddo ; enddo
5938  else if((size(data,1)==xsize_g) .and. (size(data,2)==ysize_g)) then !on_global_domain
5939  i = 0
5940  do l = 1, size(data,4) ; do k = 1, size(data,3)
5941  i = i + 1
5942  data(:,:,k,l) = data_3d(:,:,i)
5943  enddo ; enddo
5944  else
5945  call mpp_error(fatal,'error in read_data_4d_new, field '//trim(fieldname)// &
5946  ' in file '//trim(filename)//' data must be in compute or data domain')
5947  endif
5948  else
5949  i = 0
5950  do l = 1, size(data,4) ; do k = 1, size(data,3)
5951  i = i + 1
5952  data(:,:,k,l) = data_3d(:,:,i)
5953  enddo ; enddo
5954  endif
5955 
5956 end subroutine read_data_4d_new
5957 
5958 subroutine read_data_2d_ug(filename,fieldname,data,SG_domain,UG_domain,timelevel)
5959  character(len=*), intent(in) :: filename, fieldname
5960  real, dimension(:), intent(inout) :: data !2 dimensional data
5961  type(domain2d), intent(in) :: SG_domain
5962  type(domainUG), intent(in) :: UG_domain
5963  integer, intent(in) , optional :: timelevel
5964  real, dimension(:,:), allocatable :: data_2d
5965  integer :: is, ie, js, je
5966 
5967  call mpp_get_compute_domain(sg_domain, is, ie, js, je)
5968  allocate(data_2d(is:ie,js:je))
5969  call read_data_2d_new(filename,fieldname,data_2d, sg_domain, timelevel)
5970  call mpp_pass_sg_to_ug(ug_domain, data_2d, data)
5971  deallocate(data_2d)
5972 
5973 end subroutine read_data_2d_ug
5974 
5975 subroutine read_data_2d_new(filename,fieldname,data,domain,timelevel,&
5976  no_domain,position,tile_count)
5977  character(len=*), intent(in) :: filename, fieldname
5978  real, dimension(:,:), intent(inout) :: data !2 dimensional data
5979  real, dimension(size(data,1),size(data,2),1) :: data_3d
5980  type(domain2d), intent(in), optional :: domain
5981  integer, intent(in) , optional :: timelevel
5982  logical, intent(in), optional :: no_domain
5983  integer, intent(in) , optional :: position, tile_count
5984 
5985 
5986  integer :: isc,iec,jsc,jec,isd,ied,jsd,jed
5987  integer :: isg,ieg,jsg,jeg
5988  integer :: xsize_c,ysize_c,xsize_d,ysize_d
5989  integer :: xsize_g,ysize_g, ishift, jshift
5990 
5991 !#ifdef use_CRI_pointers
5992 ! pointer( p, data_3d )
5993 ! p = LOC(data)
5994 !#endif
5995 
5996  call read_data_3d_new(filename,fieldname,data_3d,domain,timelevel,&
5997  no_domain,.false., position,tile_count)
5998 
5999  if(PRESENT(domain)) then
6000  call mpp_get_global_domain( domain,isg,ieg,jsg,jeg,xsize=xsize_g,ysize=ysize_g, tile_count=tile_count, position=position)
6001  call mpp_get_compute_domain( domain,isc,iec,jsc,jec,xsize=xsize_c,ysize=ysize_c, tile_count=tile_count, position=position)
6002  call mpp_get_data_domain( domain,isd,ied,jsd,jed,xsize=xsize_d,ysize=ysize_d, tile_count=tile_count, position=position)
6003  call mpp_get_domain_shift (domain, ishift, jshift, position)
6004  if(((size(data,1)==xsize_c) .and. (size(data,2)==ysize_c))) then !on_comp_domain
6005  data(:,:) = data_3d(:,:,1)
6006  else if((size(data,1)==xsize_d) .and. (size(data,2)==ysize_d)) then !on_data_domain
6007  data(isc-isd+1:iec-isd+1,jsc-jsd+1:jec-jsd+1) = data_3d(isc-isd+1:iec-isd+1,jsc-jsd+1:jec-jsd+1,1)
6008  else if((size(data,1)==xsize_g) .and. (size(data,2)==ysize_g)) then !on_global_domain
6009  data(:,:) = data_3d(:,:,1)
6010  else
6011  call mpp_error(fatal,'error in read_data_2d_new, field '//trim(fieldname)// &
6012  ' in file '//trim(filename)//' data must be in compute or data domain')
6013  endif
6014  else
6015  data(:,:) = data_3d(:,:,1)
6016  endif
6017 
6018 end subroutine read_data_2d_new
6019 !.....................................................................
6020 subroutine read_data_1d_new(filename,fieldname,data,domain,timelevel,&
6021  no_domain, tile_count)
6022  character(len=*), intent(in) :: filename, fieldname
6023  real, dimension(:), intent(inout) :: data !1 dimensional data
6024  real, dimension(size(data,1),1,1) :: data_3d
6025  type(domain2d), intent(in), optional :: domain
6026  integer, intent(in) , optional :: timelevel
6027  logical, intent(in), optional :: no_domain
6028  integer, intent(in), optional :: tile_count
6029 #ifdef use_CRI_pointers
6030  pointer( p, data_3d )
6031  p = loc(data)
6032 #endif
6033 
6034  call read_data_3d_new(filename,fieldname,data_3d,domain,timelevel,&
6035  no_domain=no_domain, scalar_or_1d=.true., tile_count=tile_count)
6036 
6037 end subroutine read_data_1d_new
6038 !.....................................................................
6039 
6040 subroutine read_data_scalar_new(filename,fieldname,data,domain,timelevel,&
6041  no_domain, tile_count)
6043 ! this subroutine is for reading a single number
6044  character(len=*), intent(in) :: filename, fieldname
6045  real, intent(inout) :: data !zero dimension data
6046  real, dimension(1,1,1) :: data_3d
6047  type(domain2d), intent(in), optional :: domain
6048  integer, intent(in) , optional :: timelevel
6049  logical, intent(in), optional :: no_domain
6050  integer, intent(in), optional :: tile_count
6051 
6052  if(present(no_domain)) then
6053  if(.NOT. no_domain) call mpp_error(fatal, 'fms_io(read_data_scalar_new): no_domain should be true for field ' &
6054  //trim(fieldname)//' of file '//trim(filename) )
6055  end if
6056 
6057  call read_data_3d_new(filename,fieldname,data_3d,domain,timelevel,&
6058  no_domain=no_domain, scalar_or_1d=.true., tile_count=tile_count)
6059 
6060  data = data_3d(1,1,1)
6061 
6062 end subroutine read_data_scalar_new
6063 !.....................................................................
6064 
6065 function unique_axes(file, index, id_axes, siz_axes, dom)
6066  type(restart_file_type), intent(inout) :: file
6067  integer, intent(in) :: index
6068  integer, dimension(:), intent(out) :: id_axes
6069  integer, dimension(:), intent(out) :: siz_axes
6070  type(domain1d), dimension(:), intent(in), optional :: dom
6071  integer :: unique_axes
6072  type(var_type), pointer, save :: cur_var => null()
6073  integer :: i,j
6074  logical :: found
6075 
6076  unique_axes=0
6077 
6078  if(index <0 .OR. index > 4) call mpp_error(fatal,"unique_axes(fms_io_mod): index should be 1, 2, 3 or 4")
6079 
6080  do i = 1, file%nvar
6081  cur_var => file%var(i)
6082  if(cur_var%read_only) cycle
6083  if(cur_var%ndim < index) cycle
6084  found = .false.
6085  do j = 1, unique_axes
6086  if(siz_axes(j) == cur_var%gsiz(index) ) then
6087  if(PRESENT(dom)) then
6088  if(cur_var%domain_idx == id_axes(j) ) then
6089  found = .true.
6090  exit
6091  else if(cur_var%domain_idx >0 .AND. id_axes(j) >0) then
6092  if(dom(cur_var%domain_idx) .EQ. dom(id_axes(j)) ) then
6093  found = .true.
6094  exit
6095  end if
6096  end if
6097  else
6098  found = .true.
6099  exit
6100  end if
6101  end if
6102  end do
6103  if(found) then
6104  cur_var%id_axes(index) = j
6105  else
6107  if(unique_axes > max_axes) then
6108  write(error_msg,'(I3,"/",I3)') unique_axes, max_axes
6109  if(index == 1 ) then
6110  call mpp_error(fatal,'# x axes exceeded max_axes in fms_io,num_axes/max_axes= '//trim(error_msg))
6111  else if(index == 2 ) then
6112  call mpp_error(fatal,'# y axes exceeded max_axes in fms_io,num_axes/max_axes= '//trim(error_msg))
6113  else
6114  call mpp_error(fatal,'# z axes exceeded max_axes in fms_io,num_axes/max_axes= '//trim(error_msg))
6115  end if
6116  endif
6117  id_axes(unique_axes) = cur_var%domain_idx
6118  siz_axes(unique_axes) = cur_var%gsiz(index)
6119  if(siz_axes(unique_axes) > max_axis_size) then
6120  call mpp_error(fatal, 'fms_io_mod(unique_axes): size_axes is greater than max_axis_size, '//&
6121  'increase fms_io_nml variable max_axis_size to at least ', siz_axes(unique_axes))
6122  endif
6123  cur_var%id_axes(index) = unique_axes
6124  end if
6125  end do
6126 
6127  cur_var => null()
6128 
6129  return
6130 
6131 end function unique_axes
6132 
6133  !#######################################################################
6134  !#######################################################################
6135  ! --------- routines for reading distributed data ---------
6136  ! before calling these routines the domain decompostion must be set
6137  ! by calling "set_domain" with the appropriate domain2d data type
6138  !
6139  ! reading can be done either by all PEs (default) or by only the root PE
6140  ! this is controlled by namelist variable "read_all_pe".
6141 
6142  ! By default, array data is expected to be declared in data domain and no_halo
6143  !is NOT needed, however IF data is decalared in COMPUTE domain then optional NO_HALO should be .true.
6144 
6145  !#######################################################################
6146 
6147 subroutine read_data_2d ( unit, data, end)
6149  integer, intent(in) :: unit
6150  real, intent(out), dimension(isd:,jsd:) :: data
6151  logical, intent(out), optional :: end
6152  real, dimension(isg:ieg,jsg:jeg) :: gdata
6153  integer :: len
6154  logical :: no_halo
6155 
6156  include "read_data_2d.inc"
6157 end subroutine read_data_2d
6158 
6159 !#######################################################################
6160 
6161 subroutine read_ldata_2d ( unit, data, end)
6163  integer, intent(in) :: unit
6164  logical, intent(out), dimension(isd:,jsd:) :: data
6165  logical, intent(out), optional :: end
6166  logical, dimension(isg:ieg,jsg:jeg) :: gdata
6167  integer :: len
6168  logical :: no_halo
6169 
6170  include "read_data_2d.inc"
6171 end subroutine read_ldata_2d
6172 !#######################################################################
6173 
6174 subroutine read_idata_2d ( unit, data, end)
6176  integer, intent(in) :: unit
6177  integer, intent(out), dimension(isd:,jsd:) :: data
6178  logical, intent(out), optional :: end
6179  integer, dimension(isg:ieg,jsg:jeg) :: gdata
6180  integer :: len
6181  logical :: no_halo
6182 
6183  include "read_data_2d.inc"
6184 end subroutine read_idata_2d
6185 
6186 !#######################################################################
6187 
6188 #ifdef OVERLOAD_C8
6189 subroutine read_cdata_2d ( unit, data, end)
6190 
6191  integer, intent(in) :: unit
6192  complex, intent(out), dimension(isd:,jsd:) :: data
6193  logical, intent(out), optional :: end
6194  complex, dimension(isg:ieg,jsg:jeg) :: gdata
6195  integer :: len
6196  logical :: no_halo
6197 
6198  include "read_data_2d.inc"
6199 end subroutine read_cdata_2d
6200 #endif
6201 
6202 !#######################################################################
6203 
6204 subroutine read_data_3d ( unit, data, end)
6206  integer, intent(in) :: unit
6207  real, intent(out), dimension(isd:,jsd:,:) :: data
6208  logical, intent(out), optional :: end
6209  real, dimension(isg:ieg,jsg:jeg,size(data,3)) :: gdata
6210  integer :: len
6211  logical :: no_halo
6212 
6213  include "read_data_3d.inc"
6214 end subroutine read_data_3d
6215 
6216 !#######################################################################
6217 
6218 #ifdef OVERLOAD_C8
6219 subroutine read_cdata_3d ( unit, data, end)
6220 
6221  integer, intent(in) :: unit
6222  complex, intent(out), dimension(isd:,jsd:,:) :: data
6223  logical, intent(out), optional :: end
6224  complex, dimension(isg:ieg,jsg:jeg,size(data,3)) :: gdata
6225  integer :: len
6226  logical :: no_halo
6227 
6228  include "read_data_3d.inc"
6229 end subroutine read_cdata_3d
6230 #endif
6231 
6232 !#######################################################################
6233 
6234 subroutine read_data_4d ( unit, data, end)
6236  integer, intent(in) :: unit
6237  real, intent(out), dimension(isd:,jsd:,:,:) :: data
6238  logical, intent(out), optional :: end
6239  real, dimension(isg:ieg,jsg:jeg,size(data,3),size(data,4)) :: gdata
6240  integer :: len
6241  logical :: no_halo
6242 ! WARNING: memory usage with this routine could be costly
6243 
6244  include "read_data_4d.inc"
6245 end subroutine read_data_4d
6246 
6247 !#######################################################################
6248 
6249 #ifdef OVERLOAD_C8
6250 subroutine read_cdata_4d ( unit, data, end)
6251 
6252  integer, intent(in) :: unit
6253  complex, intent(out), dimension(isd:,jsd:,:,:) :: data
6254  logical, intent(out), optional :: end
6255  complex, dimension(isg:ieg,jsg:jeg,size(data,3),size(data,4)) :: gdata
6256  integer :: len
6257  logical :: no_halo
6258 ! WARNING: memory usage with this routine could be costly
6259 
6260  include "read_data_4d.inc"
6261 end subroutine read_cdata_4d
6262 #endif
6263 
6264 !#######################################################################
6265 ! -------- routines for writing distributed data --------
6266 ! before calling these routines the domain decompostion must be set
6267 ! by calling "set_domain" with the appropriate domain2d data type
6268 !#######################################################################
6269 subroutine write_data_2d ( unit, data )
6270  integer, intent(in) :: unit
6271  real, intent(in), dimension(isd:,jsd:) :: data
6272  real, dimension(isg:ieg,jsg:jeg) :: gdata
6273 
6274  include "write_data.inc"
6275 end subroutine write_data_2d
6276 
6277 !#######################################################################
6278 
6279 subroutine write_ldata_2d ( unit, data )
6281  integer, intent(in) :: unit
6282  logical, intent(in), dimension(isd:,jsd:) :: data
6283  logical, dimension(isg:ieg,jsg:jeg) :: gdata
6284 
6285  include "write_data.inc"
6286 end subroutine write_ldata_2d
6287 
6288 !#######################################################################
6289 subroutine write_idata_2d ( unit, data )
6291  integer, intent(in) :: unit
6292  integer, intent(in), dimension(isd:,jsd:) :: data
6293  integer, dimension(isg:ieg,jsg:jeg) :: gdata
6294 
6295  include "write_data.inc"
6296 end subroutine write_idata_2d
6297 
6298 !#######################################################################
6299 
6300 #ifdef OVERLOAD_C8
6301 subroutine write_cdata_2d ( unit, data )
6302 
6303  integer, intent(in) :: unit
6304  complex, intent(in), dimension(isd:,jsd:) :: data
6305  complex, dimension(isg:ieg,jsg:jeg) :: gdata
6306 
6307  include "write_data.inc"
6308 end subroutine write_cdata_2d
6309 #endif
6310 
6311 !#######################################################################
6312 
6313 subroutine write_data_3d ( unit, data )
6315  integer, intent(in) :: unit
6316  real, intent(in), dimension(isd:,jsd:,:) :: data
6317  real, dimension(isg:ieg,jsg:jeg,size(data,3)) :: gdata
6318 
6319  include "write_data.inc"
6320 end subroutine write_data_3d
6321 
6322 !#######################################################################
6323 
6324 #ifdef OVERLOAD_C8
6325 subroutine write_cdata_3d ( unit, data )
6326 
6327  integer, intent(in) :: unit
6328  complex, intent(in), dimension(isd:,jsd:,:) :: data
6329  complex, dimension(isg:ieg,jsg:jeg,size(data,3)) :: gdata
6330 
6331  include "write_data.inc"
6332 end subroutine write_cdata_3d
6333 #endif
6334 
6335 !#######################################################################
6336 subroutine write_data_4d ( unit, data )
6338  integer, intent(in) :: unit
6339  real, intent(in), dimension(isd:,jsd:,:,:) :: data
6340  real, dimension(isg:ieg,jsg:jeg,size(data,3),size(data,4)) :: gdata
6341  integer :: n
6342 
6343  if (.not.associated(current_domain)) &
6344  call mpp_error(fatal,'fms_io(write_data_4d): need to call set_domain ')
6345 
6346 ! get the global data and write only on root pe
6347 ! do this one field at a time to save memory
6348  do n = 1, size(data,4)
6349  call mpp_global_field ( current_domain, data(:,:,:,n), gdata(:,:,:,n) )
6350  enddo
6351  if ( mpp_pe() == mpp_root_pe() ) write (unit) gdata
6352 end subroutine write_data_4d
6353 
6354 !#######################################################################
6355 
6356 #ifdef OVERLOAD_C8
6357 subroutine write_cdata_4d ( unit, data )
6358 
6359  integer, intent(in) :: unit
6360  complex, intent(in), dimension(isd:,jsd:,:,:) :: data
6361  complex, dimension(isg:ieg,jsg:jeg,size(data,3),size(data,4)) :: gdata
6362  integer :: n
6363 
6364  if (.not.associated(current_domain)) call mpp_error(fatal, 'fms_io(write_cdata_4d): need to call set_domain')
6365 
6366 ! get the global data and write only on root pe
6367 ! do this one field at a time to save memory
6368  do n = 1, size(data,4)
6369  call mpp_global_field ( current_domain, data(:,:,:,n), gdata(:,:,:,n) )
6370  enddo
6371  if ( mpp_pe() == mpp_root_pe() ) write (unit) gdata
6372 end subroutine write_cdata_4d
6373 #endif
6374 
6375 !#######################################################################
6376 ! private routines (read_eof,do_read)
6377 ! this routine is called when an EOF is found while
6378 ! reading a distributed data file using read_data
6379 
6380 subroutine read_eof (end_found)
6381  logical, intent(out), optional :: end_found
6382 
6383  if (present(end_found))then
6384  end_found = .true.
6385  else
6386  call mpp_error(fatal,'fms_io(read_eof): unexpected EOF')
6387  endif
6388 end subroutine read_eof
6389 
6390 !#######################################################################
6391 ! determines if current pe should read data
6392 ! checks namelist variable read_all_pe
6393 
6394 function do_read ( )
6395  logical :: do_read
6396  do_read = mpp_pe() == mpp_root_pe() .or. read_all_pe
6397 end function do_read
6398 
6399 !!#######################################################################
6400 
6401 subroutine reset_field_name(fileObj, id_field, name)
6402  type(restart_file_type), intent(inout) :: fileobj
6403  integer, intent(in) :: id_field
6404  character(len=*), intent(in) :: name
6405 
6406  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_name): " // &
6407  "restart_file_type data must be initialized by calling register_restart_field before using it")
6408 
6409  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6410  "fms_io(reset_field_name): id_field should be positive integer and "// &
6411  "no larger than number of fields in the file "//trim(fileobj%name) )
6412 
6413  fileobj%var(id_field)%name = trim(name)
6414 
6415 end subroutine reset_field_name
6416 
6417 !#######################################################################
6418 
6419 subroutine reset_field_pointer_r0d(fileObj, id_field, data)
6420  type(restart_file_type), intent(inout) :: fileObj
6421  integer, intent(in) :: id_field
6422  real, intent(in), target :: data
6423 
6424  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r0d): " // &
6425  "restart_file_type data must be initialized by calling register_restart_field before using it")
6426 
6427  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6428  "fms_io(reset_field_pointer_r0d): id_field should be positive integer and "// &
6429  "no larger than number of fields in the file "//trim(fileobj%name) )
6430  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6431  "fms_io(reset_field_pointer_r0d): one-level reset_field_pointer is called, but "//&
6432  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6433 
6434  fileobj%p0dr(1, id_field)%p => data
6435 
6436 end subroutine reset_field_pointer_r0d
6437 
6438 !#######################################################################
6439 
6440 subroutine reset_field_pointer_r1d(fileObj, id_field, data)
6441  type(restart_file_type), intent(inout) :: fileObj
6442  integer, intent(in) :: id_field
6443  real, dimension(:), intent(in), target :: data
6444 
6445  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r1d): " // &
6446  "restart_file_type data must be initialized by calling register_restart_field before using it")
6447 
6448  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6449  "fms_io(reset_field_pointer_r1d): id_field should be positive integer and "// &
6450  "no larger than number of fields in the file "//trim(fileobj%name) )
6451  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6452  "fms_io(reset_field_pointer_r1d): one-level reset_field_pointer is called, but "//&
6453  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6454 
6455  fileobj%p1dr(1, id_field)%p => data
6456 
6457 end subroutine reset_field_pointer_r1d
6458 
6459 
6460 !#######################################################################
6461 subroutine reset_field_pointer_r2d(fileObj, id_field, data)
6462  type(restart_file_type), intent(inout) :: fileObj
6463  integer, intent(in) :: id_field
6464  real, dimension(:,:), intent(in), target :: data
6465 
6466  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r2d): " // &
6467  "restart_file_type data must be initialized by calling register_restart_field before using it")
6468 
6469  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6470  "fms_io(reset_field_pointer_r2d): id_field should be positive integer and "// &
6471  "no larger than number of fields in the file "//trim(fileobj%name) )
6472  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6473  "fms_io(reset_field_pointer_r2d): one-level reset_field_pointer is called, but "//&
6474  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6475 
6476  fileobj%p2dr(1, id_field)%p => data
6477 
6478 end subroutine reset_field_pointer_r2d
6479 
6480 !#######################################################################
6481 
6482 subroutine reset_field_pointer_r3d(fileObj, id_field, data)
6483  type(restart_file_type), intent(inout) :: fileObj
6484  integer, intent(in) :: id_field
6485  real, dimension(:,:,:), intent(in), target :: data
6486 
6487  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r3d): " // &
6488  "restart_file_type data must be initialized by calling register_restart_field before using it")
6489 
6490  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6491  "fms_io(reset_field_pointer_r3d): id_field should be positive integer and "// &
6492  "no larger than number of fields in the file "//trim(fileobj%name) )
6493  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6494  "fms_io(reset_field_pointer_r3d): one-level reset_field_pointer is called, but "//&
6495  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6496 
6497  fileobj%p3dr(1, id_field)%p => data
6498 
6499 end subroutine reset_field_pointer_r3d
6500 
6501 !#######################################################################
6502 
6503 subroutine reset_field_pointer_r4d(fileObj, id_field, data)
6504  type(restart_file_type), intent(inout) :: fileObj
6505  integer, intent(in) :: id_field
6506  real, dimension(:,:,:,:), intent(in), target :: data
6507 
6508  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r4d): " // &
6509  "restart_file_type data must be initialized by calling register_restart_field before using it")
6510 
6511  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6512  "fms_io(reset_field_pointer_r4d): id_field should be positive integer and "// &
6513  "no larger than number of fields in the file "//trim(fileobj%name) )
6514  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6515  "fms_io(reset_field_pointer_r4d): one-level reset_field_pointer is called, but "//&
6516  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6517 
6518  fileobj%p4dr(1, id_field)%p => data
6519 
6520 end subroutine reset_field_pointer_r4d
6521 
6522 
6523 !#######################################################################
6524 
6525 subroutine reset_field_pointer_i0d(fileObj, id_field, data)
6526  type(restart_file_type), intent(inout) :: fileObj
6527  integer, intent(in) :: id_field
6528  integer, intent(in), target :: data
6529 
6530  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i0d): " // &
6531  "restart_file_type data must be initialized by calling register_restart_field before using it")
6532 
6533  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6534  "fms_io(reset_field_pointer_i0d): id_field should be positive integer and "// &
6535  "no larger than number of fields in the file "//trim(fileobj%name) )
6536  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6537  "fms_io(reset_field_pointer_i0d): one-level reset_field_pointer is called, but "//&
6538  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6539 
6540  fileobj%p0di(1, id_field)%p => data
6541 
6542 end subroutine reset_field_pointer_i0d
6543 
6544 !#######################################################################
6545 
6546 subroutine reset_field_pointer_i1d(fileObj, id_field, data)
6547  type(restart_file_type), intent(inout) :: fileObj
6548  integer, intent(in) :: id_field
6549  integer, dimension(:), intent(in), target :: data
6550 
6551  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i1d): " // &
6552  "restart_file_type data must be initialized by calling register_restart_field before using it")
6553 
6554  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6555  "fms_io(reset_field_pointer_i1d): id_field should be positive integer and "// &
6556  "no larger than number of fields in the file "//trim(fileobj%name) )
6557  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6558  "fms_io(reset_field_pointer_i1d): one-level reset_field_pointer is called, but "//&
6559  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6560 
6561  fileobj%p1di(1, id_field)%p => data
6562 
6563 end subroutine reset_field_pointer_i1d
6564 
6565 
6566 !#######################################################################
6567 subroutine reset_field_pointer_i2d(fileObj, id_field, data)
6568  type(restart_file_type), intent(inout) :: fileObj
6569  integer, intent(in) :: id_field
6570  integer, dimension(:,:), intent(in), target :: data
6571 
6572  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i2d): " // &
6573  "restart_file_type data must be initialized by calling register_restart_field before using it")
6574 
6575  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6576  "fms_io(reset_field_pointer_i2d): id_field should be positive integer and "// &
6577  "no larger than number of fields in the file "//trim(fileobj%name) )
6578  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6579  "fms_io(reset_field_pointer_i2d): one-level reset_field_pointer is called, but "//&
6580  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6581 
6582  fileobj%p2di(1, id_field)%p => data
6583 
6584 end subroutine reset_field_pointer_i2d
6585 
6586 !#######################################################################
6587 
6588 subroutine reset_field_pointer_i3d(fileObj, id_field, data)
6589  type(restart_file_type), intent(inout) :: fileObj
6590  integer, intent(in) :: id_field
6591  integer, dimension(:,:,:), intent(in), target :: data
6592 
6593  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i3d): " // &
6594  "restart_file_type data must be initialized by calling register_restart_field before using it")
6595 
6596  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6597  "fms_io(reset_field_pointer_i3d): id_field should be positive integer and "// &
6598  "no larger than number of fields in the file "//trim(fileobj%name) )
6599  if(fileobj%var(id_field)%siz(4) .NE. 1) call mpp_error(fatal, &
6600  "fms_io(reset_field_pointer_i3d): one-level reset_field_pointer is called, but "//&
6601  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not one level" )
6602 
6603  fileobj%p3di(1, id_field)%p => data
6604 
6605 end subroutine reset_field_pointer_i3d
6606 
6607 !#######################################################################
6608 
6609 subroutine reset_field_pointer_r0d_2level(fileObj, id_field, data1, data2)
6610  type(restart_file_type), intent(inout) :: fileObj
6611  integer, intent(in) :: id_field
6612  real, intent(in), target :: data1, data2
6613 
6614  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r0d_2level): " // &
6615  "restart_file_type data must be initialized by calling register_restart_field before using it")
6616 
6617  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6618  "fms_io(reset_field_pointer_r0d_2level): id_field should be positive integer and "// &
6619  "no larger than number of fields in the file "//trim(fileobj%name) )
6620  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6621  "fms_io(reset_field_pointer_r0d_2level): two-level reset_field_pointer is called, but "//&
6622  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6623 
6624  fileobj%p0dr(1, id_field)%p => data1
6625  fileobj%p0dr(2, id_field)%p => data2
6626 
6627 end subroutine reset_field_pointer_r0d_2level
6628 
6629 !#######################################################################
6630 
6631 subroutine reset_field_pointer_r1d_2level(fileObj, id_field, data1, data2)
6632  type(restart_file_type), intent(inout) :: fileObj
6633  integer, intent(in) :: id_field
6634  real, dimension(:), intent(in), target :: data1, data2
6635 
6636  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r1d_2level): " // &
6637  "restart_file_type data must be initialized by calling register_restart_field before using it")
6638 
6639  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6640  "fms_io(reset_field_pointer_r1d_2level): id_field should be positive integer and "// &
6641  "no larger than number of fields in the file "//trim(fileobj%name) )
6642  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6643  "fms_io(reset_field_pointer_r1d_2level): two-level reset_field_pointer is called, but "//&
6644  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6645 
6646  fileobj%p1dr(1, id_field)%p => data1
6647  fileobj%p1dr(2, id_field)%p => data2
6648 
6649 end subroutine reset_field_pointer_r1d_2level
6650 
6651 !#######################################################################
6652 
6653 subroutine reset_field_pointer_r2d_2level(fileObj, id_field, data1, data2)
6654  type(restart_file_type), intent(inout) :: fileObj
6655  integer, intent(in) :: id_field
6656  real, dimension(:,:), intent(in), target :: data1, data2
6657 
6658  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r2d_2level): " // &
6659  "restart_file_type data must be initialized by calling register_restart_field before using it")
6660 
6661  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6662  "fms_io(reset_field_pointer_r2d_2level): id_field should be positive integer and "// &
6663  "no larger than number of fields in the file "//trim(fileobj%name) )
6664  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6665  "fms_io(reset_field_pointer_r2d_2level): two-level reset_field_pointer is called, but "//&
6666  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6667 
6668  fileobj%p2dr(1, id_field)%p => data1
6669  fileobj%p2dr(2, id_field)%p => data2
6670 
6671 end subroutine reset_field_pointer_r2d_2level
6672 
6673 !#######################################################################
6674 
6675 subroutine reset_field_pointer_r3d_2level(fileObj, id_field, data1, data2)
6676  type(restart_file_type), intent(inout) :: fileObj
6677  integer, intent(in) :: id_field
6678  real, dimension(:,:,:), intent(in), target :: data1, data2
6679 
6680  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_r3d_2level): " // &
6681  "restart_file_type data must be initialized by calling register_restart_field before using it")
6682 
6683  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6684  "fms_io(reset_field_pointer_r3d_2level): id_field should be positive integer and "// &
6685  "no larger than number of fields in the file "//trim(fileobj%name) )
6686  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6687  "fms_io(reset_field_pointer_r3d_2level): two-level reset_field_pointer is called, but "//&
6688  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6689 
6690  fileobj%p3dr(1, id_field)%p => data1
6691  fileobj%p3dr(2, id_field)%p => data2
6692 
6693 end subroutine reset_field_pointer_r3d_2level
6694 
6695 !#######################################################################
6696 
6697 subroutine reset_field_pointer_i0d_2level(fileObj, id_field, data1, data2)
6698  type(restart_file_type), intent(inout) :: fileObj
6699  integer, intent(in) :: id_field
6700  integer, intent(in), target :: data1, data2
6701 
6702  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i0d_2level): " // &
6703  "restart_file_type data must be initialized by calling register_restart_field before using it")
6704 
6705  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6706  "fms_io(reset_field_pointer_i0d_2level): id_field should be positive integer and "// &
6707  "no larger than number of fields in the file "//trim(fileobj%name) )
6708  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6709  "fms_io(reset_field_pointer_i0d_2level): two-level reset_field_pointer is called, but "//&
6710  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6711 
6712  fileobj%p0di(1, id_field)%p => data1
6713  fileobj%p0di(2, id_field)%p => data2
6714 
6715 end subroutine reset_field_pointer_i0d_2level
6716 
6717 !#######################################################################
6718 
6719 subroutine reset_field_pointer_i1d_2level(fileObj, id_field, data1, data2)
6720  type(restart_file_type), intent(inout) :: fileObj
6721  integer, intent(in) :: id_field
6722  integer, dimension(:), intent(in), target :: data1, data2
6723 
6724  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i1d_2level): " // &
6725  "restart_file_type data must be initialized by calling register_restart_field before using it")
6726 
6727  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6728  "fms_io(reset_field_pointer_i1d_2level): id_field should be positive integer and "// &
6729  "no larger than number of fields in the file "//trim(fileobj%name) )
6730  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6731  "fms_io(reset_field_pointer_i1d_2level): two-level reset_field_pointer is called, but "//&
6732  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6733 
6734  fileobj%p1di(1, id_field)%p => data1
6735  fileobj%p1di(2, id_field)%p => data2
6736 
6737 end subroutine reset_field_pointer_i1d_2level
6738 
6739 !#######################################################################
6740 
6741 subroutine reset_field_pointer_i2d_2level(fileObj, id_field, data1, data2)
6742  type(restart_file_type), intent(inout) :: fileObj
6743  integer, intent(in) :: id_field
6744  integer, dimension(:,:), intent(in), target :: data1, data2
6745 
6746  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i2d_2level): " // &
6747  "restart_file_type data must be initialized by calling register_restart_field before using it")
6748 
6749  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6750  "fms_io(reset_field_pointer_i2d_2level): id_field should be positive integer and "// &
6751  "no larger than number of fields in the file "//trim(fileobj%name) )
6752  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6753  "fms_io(reset_field_pointer_i2d_2level): two-level reset_field_pointer is called, but "//&
6754  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6755 
6756  fileobj%p2di(1, id_field)%p => data1
6757  fileobj%p2di(2, id_field)%p => data2
6758 
6759 end subroutine reset_field_pointer_i2d_2level
6760 
6761 !#######################################################################
6762 
6763 subroutine reset_field_pointer_i3d_2level(fileObj, id_field, data1, data2)
6764  type(restart_file_type), intent(inout) :: fileObj
6765  integer, intent(in) :: id_field
6766  integer, dimension(:,:,:), intent(in), target :: data1, data2
6767 
6768  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(reset_field_pointer_i3d_2level): " // &
6769  "restart_file_type data must be initialized by calling register_restart_field before using it")
6770 
6771  if(id_field < 0 .OR. id_field > fileobj%nvar) call mpp_error(fatal, &
6772  "fms_io(reset_field_pointer_i3d_2level): id_field should be positive integer and "// &
6773  "no larger than number of fields in the file "//trim(fileobj%name) )
6774  if(fileobj%var(id_field)%siz(4) .NE. 2) call mpp_error(fatal, &
6775  "fms_io(reset_field_pointer_i3d_2level): two-level reset_field_pointer is called, but "//&
6776  "field "//trim(fileobj%var(id_field)%name)//" of file "//trim(fileobj%name)//" is not two level" )
6777 
6778  fileobj%p3di(1, id_field)%p => data1
6779  fileobj%p3di(2, id_field)%p => data2
6780 
6781 end subroutine reset_field_pointer_i3d_2level
6782 
6783 !#########################################################################
6784 ! This function returns .true. if the field referred to by id has
6785 ! initialized from a restart file, and .false. otherwise.
6786 !
6787 ! Arguments: id - A integer that is the index of the field in fileObj.
6788 ! (in) fileObj - The control structure returned by a previous call to
6789 ! register_restart_field
6790 function query_initialized_id(fileObj, id)
6791  type(restart_file_type), intent(in) :: fileobj
6792  integer, intent(in) :: id
6793 
6794  logical :: query_initialized_id
6795 
6796  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(query_initialized_id): " // &
6797  "restart_file_type data must be initialized by calling register_restart_field before using it")
6798 
6799  if(id < 1 .OR. id > fileobj%nvar) call mpp_error(fatal, "fms_io(query_initialized_id): " // &
6800  "argument id must be between 1 and nvar in the restart_file_type object")
6801 
6802  query_initialized_id = fileobj%var(id)%initialized
6803 
6804  return
6805 
6806 end function query_initialized_id
6807 
6808 !#########################################################################
6809 ! This function returns .true. if the field referred to by name has
6810 ! initialized from a restart file, and .false. otherwise.
6811 !
6812 ! Arguments: name - A pointer to the field that is being queried.
6813 ! (in) fileObj - The control structure returned by a previous call to
6814 ! register_restart_field
6815 function query_initialized_name(fileObj, name)
6816  type(restart_file_type), intent(inout) :: fileobj
6817  character(len=*), intent(in) :: name
6818 
6819  logical :: query_initialized_name
6820 
6821  integer :: m
6822 
6823  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(query_initialized_name): " // &
6824  "restart_file_type data must be initialized by calling register_restart_field before using it")
6825 
6826  query_initialized_name = .false.
6827  do m=1,fileobj%nvar
6828  if (trim(name) == fileobj%var(m)%name) then
6829  if (fileobj%var(m)%initialized) query_initialized_name = .true.
6830  exit
6831  endif
6832  enddo
6833 ! Assume that you are going to initialize it now, so set flag to initialized if
6834 ! queried again.
6835  if ((m>fileobj%nvar) .and. (mpp_pe() == mpp_root_pe())) then
6836  call mpp_error(note,"fms_io(query_initialized_name): Unknown restart variable "//name// &
6837  " queried for initialization.")
6838  end if
6839 
6840 end function query_initialized_name
6841 
6842 !#########################################################################
6843 ! This function returns 1 if the field pointed to by f_ptr has
6844 ! initialized from a restart file, and 0 otherwise. If f_ptr is
6845 ! NULL, it tests whether the entire restart file has been success-
6846 ! fully read.
6847 !
6848 ! Arguments: f_ptr - A pointer to the field that is being queried.
6849 ! (in) name - The name of the field that is being queried.
6850 ! (in) CS - The control structure returned by a previous call to
6851 ! restart_init.
6852 function query_initialized_r2d(fileObj, f_ptr, name)
6853  type(restart_file_type), intent(inout) :: fileobj
6854  real, dimension(:,:), target, intent(in) :: f_ptr
6855  character(len=*), intent(in) :: name
6856 
6857  logical :: query_initialized_r2d
6858  integer :: m
6859 
6860  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(query_initialized_r2d): " // &
6861  "restart_file_type data must be initialized by calling register_restart_field before using it")
6862 
6863  query_initialized_r2d = .false.
6864  do m=1, fileobj%nvar
6865  if (ASSOCIATED(fileobj%p2dr(1,m)%p,f_ptr)) then
6866  if (fileobj%var(m)%initialized) query_initialized_r2d = .true.
6867  exit
6868  endif
6869  enddo
6870  ! Assume that you are going to initialize it now, so set flag to initialized if
6871  ! queried again.
6872  if (m>fileobj%nvar) then
6873  if (mpp_pe() == mpp_root_pe() ) call mpp_error(note, "fms_io(query_initialized_r2d): Unable to find "// &
6874  trim(name)//" queried by pointer, "//"probably because of the suspect comparison of pointers by ASSOCIATED.")
6876  if (mpp_pe() == mpp_root_pe() .AND. query_initialized_r2d) call mpp_error(note, &
6877  "fms_io(query_initialized_r2d): "//trim(name)// " initialization confirmed by name.")
6878  endif
6879 
6880  return
6881 
6882 end function query_initialized_r2d
6883 
6884 !#########################################################################
6885 ! This function returns 1 if the field pointed to by f_ptr has
6886 ! initialized from a restart file, and 0 otherwise. If f_ptr is
6887 ! NULL, it tests whether the entire restart file has been success-
6888 ! fully read.
6889 !
6890 ! Arguments: f_ptr - A pointer to the field that is being queried.
6891 ! (in) name - The name of the field that is being queried.
6892 ! (in) CS - The control structure returned by a previous call to
6893 ! restart_init.
6894 function query_initialized_r3d(fileObj, f_ptr, name)
6895  type(restart_file_type), intent(inout) :: fileobj
6896  real, dimension(:,:,:), target, intent(in) :: f_ptr
6897  character(len=*), intent(in) :: name
6898 
6899  logical :: query_initialized_r3d
6900  integer :: m
6901 
6902  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(query_initialized_r3d): " // &
6903  "restart_file_type data must be initialized by calling register_restart_field before using it")
6904 
6905  query_initialized_r3d = .false.
6906  do m=1, fileobj%nvar
6907  if (ASSOCIATED(fileobj%p3dr(1,m)%p,f_ptr)) then
6908  if (fileobj%var(m)%initialized) query_initialized_r3d = .true.
6909  exit
6910  endif
6911  enddo
6912  ! Assume that you are going to initialize it now, so set flag to initialized if
6913  ! queried again.
6914  if (m>fileobj%nvar) then
6915  if (mpp_pe() == mpp_root_pe() ) call mpp_error(note, "fms_io(query_initialized_r3d): Unable to find "// &
6916  trim(name)//" queried by pointer, "//"probably because of the suspect comparison of pointers by ASSOCIATED.")
6918  if (mpp_pe() == mpp_root_pe() .AND. query_initialized_r3d) call mpp_error(note, &
6919  "fms_io(query_initialized_r3d): "//trim(name)// " initialization confirmed by name.")
6920  endif
6921 
6922  return
6923 
6924 end function query_initialized_r3d
6925 
6926 
6927 !#########################################################################
6928 ! This function returns 1 if the field pointed to by f_ptr has
6929 ! initialized from a restart file, and 0 otherwise. If f_ptr is
6930 ! NULL, it tests whether the entire restart file has been success-
6931 ! fully read.
6932 !
6933 ! Arguments: f_ptr - A pointer to the field that is being queried.
6934 ! (in) name - The name of the field that is being queried.
6935 ! (in) CS - The control structure returned by a previous call to
6936 ! restart_init.
6937 function query_initialized_r4d(fileObj, f_ptr, name)
6938  type(restart_file_type), intent(inout) :: fileobj
6939  real, dimension(:,:,:,:), target, intent(in) :: f_ptr
6940  character(len=*), intent(in) :: name
6941 
6942  logical :: query_initialized_r4d
6943  integer :: m
6944 
6945  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(query_initialized_r4d): " // &
6946  "restart_file_type data must be initialized by calling register_restart_field before using it")
6947 
6948  query_initialized_r4d = .false.
6949  do m=1, fileobj%nvar
6950  if (ASSOCIATED(fileobj%p4dr(1,m)%p,f_ptr)) then
6951  if (fileobj%var(m)%initialized) query_initialized_r4d = .true.
6952  exit
6953  endif
6954  enddo
6955  ! Assume that you are going to initialize it now, so set flag to initialized if
6956  ! queried again.
6957  if (m>fileobj%nvar) then
6958  if (mpp_pe() == mpp_root_pe() ) call mpp_error(note, "fms_io(query_initialized_r4d): Unable to find "// &
6959  trim(name)//" queried by pointer, "//"probably because of the suspect comparison of pointers by ASSOCIATED.")
6961  if (mpp_pe() == mpp_root_pe() .AND. query_initialized_r4d) call mpp_error(note, &
6962  "fms_io(query_initialized_r4d): "//trim(name)// " initialization confirmed by name.")
6963  endif
6964 
6965  return
6966 
6967 end function query_initialized_r4d
6968 
6969 !#########################################################################
6970 ! This function sets that a variable has been initialized for future queries.
6971 !
6972 ! Arguments: name - A pointer to the field whose initialization status is being set.
6973 ! (in) fileObj - The control structure returned by a previous call to
6974 ! register_restart_field
6975 subroutine set_initialized_id(fileObj, id, is_set)
6976  type(restart_file_type), intent(inout) :: fileObj
6977  integer , intent(in) :: id
6978  logical, optional, intent(in) :: is_set
6979 
6980  logical :: set_val
6981  integer :: m
6982 
6983  set_val = .true.
6984  if (present(is_set)) set_val = is_set
6985 
6986  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(set_initialized_id): " // &
6987  "restart_file_type data must be initialized by calling set_restart_field before using it")
6988 
6989  if(id < 1 .OR. id > fileobj%nvar) call mpp_error(fatal, "fms_io(set_initialized_id): " // &
6990  "argument id must be between 1 and nvar in the restart_file_type object")
6991 
6992  fileobj%var(id)%initialized = set_val
6993 
6994 
6995 end subroutine set_initialized_id
6996 
6997 !#########################################################################
6998 ! This function sets that a variable has been initialized for future queries.
6999 !
7000 ! Arguments: name - A pointer to the field whose initialization status is being set.
7001 ! (in) fileObj - The control structure returned by a previous call to
7002 ! register_restart_field
7003 subroutine set_initialized_name(fileObj, name, is_set)
7004  type(restart_file_type), intent(inout) :: fileObj
7005  character(len=*), intent(in) :: name
7006  logical, optional, intent(in) :: is_set
7007 
7008  logical :: set_val
7009  integer :: m
7010 
7011  set_val = .true.
7012  if (present(is_set)) set_val = is_set
7013 
7014  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(set_initialized_name): " // &
7015  "restart_file_type data must be initialized by calling set_restart_field before using it")
7016 
7017  do m=1,fileobj%nvar
7018  if (trim(name) == fileobj%var(m)%name) then
7019  fileobj%var(m)%initialized = set_val
7020  exit
7021  endif
7022  enddo
7023 
7024  if (m>fileobj%nvar) then
7025  call mpp_error(note,"fms_io(set_initialized_name): Unknown restart variable "//name// &
7026  " attempted to set initialization.")
7027  end if
7028 
7029 end subroutine set_initialized_name
7030 
7031 !#########################################################################
7032 ! This function sets that a variable has been initialized for future queries.
7033 !
7034 ! Arguments: name - A pointer to the field whose initialization status is being set.
7035 ! (in) fileObj - The control structure returned by a previous call to
7036 ! register_restart_field
7037 subroutine set_initialized_r2d(fileObj, f_ptr, name, is_set)
7038  type(restart_file_type), intent(inout) :: fileObj
7039  real, dimension(:,:), target, intent(in) :: f_ptr
7040  character(len=*), intent(in) :: name
7041  logical, optional, intent(in) :: is_set
7042  logical :: set_val
7043  integer :: m
7044 
7045  set_val = .true.
7046  if (present(is_set)) set_val = is_set
7047 
7048  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(set_initialized_r2d): " // &
7049  "restart_file_type data must be initialized by calling set_restart_field before using it")
7050 
7051  do m=1, fileobj%nvar
7052  if (ASSOCIATED(fileobj%p2dr(1,m)%p,f_ptr)) then
7053  fileobj%var(m)%initialized = set_val
7054  return
7055  endif
7056  enddo
7057 
7058  if (m>fileobj%nvar .AND. mpp_pe() == mpp_root_pe() ) then
7059  call mpp_error(note,"fms_io(set_initialized_r2d): Unable to find "// &
7060  trim(name)//" queried by pointer, "//"probably because of the suspect comparison of pointers by ASSOCIATED"// &
7061  " when attempting to set initialization.")
7062  end if
7063 
7064  do m=1,fileobj%nvar
7065  if (trim(name) == fileobj%var(m)%name) then
7066  fileobj%var(m)%initialized = set_val
7067  return
7068  endif
7069  enddo
7070 
7071  if (m>fileobj%nvar .AND. mpp_pe() == mpp_root_pe() ) then
7072  call mpp_error(note,"fms_io(set_initialized_r2d): Unknown restart variable "//name// &
7073  " attempted to set initialization.")
7074  end if
7075 
7076 end subroutine set_initialized_r2d
7077 
7078 !#########################################################################
7079 ! This function sets that a variable has been initialized for future queries.
7080 !
7081 ! Arguments: name - A pointer to the field whose initialization status is being set.
7082 ! (in) fileObj - The control structure returned by a previous call to
7083 ! register_restart_field
7084 subroutine set_initialized_r3d(fileObj, f_ptr, name, is_set)
7085  type(restart_file_type), intent(inout) :: fileObj
7086  real, dimension(:,:,:), target, intent(in) :: f_ptr
7087  character(len=*), intent(in) :: name
7088  logical, optional, intent(in) :: is_set
7089  logical :: set_val
7090  integer :: m
7091 
7092  set_val = .true.
7093  if (present(is_set)) set_val = is_set
7094 
7095  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(set_initialized_r3d): " // &
7096  "restart_file_type data must be initialized by calling set_restart_field before using it")
7097 
7098  do m=1, fileobj%nvar
7099  if (ASSOCIATED(fileobj%p3dr(1,m)%p,f_ptr)) then
7100  fileobj%var(m)%initialized = set_val
7101  return
7102  endif
7103  enddo
7104 
7105  if (m>fileobj%nvar .AND. mpp_pe() == mpp_root_pe() ) then
7106  call mpp_error(note,"fms_io(set_initialized_r3d): Unable to find "// &
7107  trim(name)//" queried by pointer, "//"probably because of the suspect comparison of pointers by ASSOCIATED"//&
7108  " when attempting to set initialization.")
7109  end if
7110 
7111  do m=1,fileobj%nvar
7112  if (trim(name) == fileobj%var(m)%name) then
7113  fileobj%var(m)%initialized = set_val
7114  return
7115  endif
7116  enddo
7117 
7118  if (m>fileobj%nvar .AND. mpp_pe() == mpp_root_pe() ) then
7119  call mpp_error(note,"fms_io(set_initialized_r3d): Unknown restart variable "//name// &
7120  " attempted to set initialization.")
7121  end if
7122 
7123 end subroutine set_initialized_r3d
7124 
7125 
7126 !#########################################################################
7127 ! This function sets that a variable has been initialized for future queries.
7128 !
7129 ! Arguments: name - A pointer to the field whose initialization status is being set.
7130 ! (in) fileObj - The control structure returned by a previous call to
7131 ! register_restart_field
7132 subroutine set_initialized_r4d(fileObj, f_ptr, name, is_set)
7133  type(restart_file_type), intent(inout) :: fileObj
7134  real, dimension(:,:,:,:), target, intent(in) :: f_ptr
7135  character(len=*), intent(in) :: name
7136  logical, optional, intent(in) :: is_set
7137  logical :: set_val
7138  integer :: m
7139 
7140  set_val = .true.
7141  if (present(is_set)) set_val = is_set
7142 
7143  if (.not.associated(fileobj%var)) call mpp_error(fatal, "fms_io(set_initialized_r4d): " // &
7144  "restart_file_type data must be initialized by calling set_restart_field before using it")
7145 
7146  do m=1, fileobj%nvar
7147  if (ASSOCIATED(fileobj%p4dr(1,m)%p,f_ptr)) then
7148  fileobj%var(m)%initialized = set_val
7149  return
7150  endif
7151  enddo
7152 
7153  if (m>fileobj%nvar .AND. mpp_pe() == mpp_root_pe() ) then
7154  call mpp_error(note,"fms_io(set_initialized_r4d): Unable to find "// &
7155  trim(name)//" queried by pointer, "//"probably because of the suspect comparison of pointers by ASSOCIATED"//&
7156  " when attempting to set initialization.")
7157  end if
7158 
7159  do m=1,fileobj%nvar
7160  if (trim(name) == fileobj%var(m)%name) then
7161  fileobj%var(m)%initialized = set_val
7162  return
7163  endif
7164  enddo
7165 
7166  if (m>fileobj%nvar .AND. mpp_pe() == mpp_root_pe() ) then
7167  call mpp_error(note,"fms_io(set_initialized_r4d): Unknown restart variable "//name// &
7168  " attempted to set initialization.")
7169  end if
7170 
7171 end subroutine set_initialized_r4d
7172 
7173 !#######################################################################
7174 !#######################################################################
7175 !
7176 ! routines for opening specific types of files:
7177 !
7178 ! form action
7179 ! open_namelist_file MPP_ASCII MPP_RDONLY
7180 ! open restart_file MPP_NATIVE
7181 ! open_ieee32_file MPP_IEEE32
7182 !
7183 ! all have: access=MPP_SEQUENTIAL, threading=MPP_SINGLE, nohdrs=.true.
7184 ! use the close_file interface to close these files
7185 !
7186 ! if other types of files need to be opened the mpp_open and
7187 ! mpp_close routines in the mpp_io_mod should be used
7188 !
7189 !#######################################################################
7190 
7191 
7192 ! <FUNCTION NAME="open_namelist_file">
7193 ! <DESCRIPTION>
7194 ! Opens single namelist file for reading only by all PEs
7195 ! the default file opened is called "input.nml".
7196 ! </DESCRIPTION>
7197 ! <IN NAME="file" TYPE="character">
7198 ! name of the file to be opened
7199 ! </IN>
7200 ! <OUT NAME="unit" TYPE="integer">
7201 ! unit number returned by this function
7202 ! </OUT>
7203 function open_namelist_file (file) result (unit)
7204  character(len=*), intent(in), optional :: file
7205  integer :: unit
7206 ! local variables necessary for nesting code and alternate input.nmls
7207  character(len=32) :: pelist_name
7208  character(len=128) :: filename
7209 
7210 #ifdef INTERNAL_FILE_NML
7211  if(show_open_namelist_file_warning) call mpp_error(warning, "fms_io_mod: open_namelist_file should not be called when INTERNAL_FILE_NML is defined")
7212 #endif
7213 
7214  if (.not.module_is_initialized) call fms_io_init ( )
7215  if (present(file)) then
7216  call mpp_open ( unit, file, form=mpp_ascii, action=mpp_rdonly, &
7217  access=mpp_sequential, threading=mpp_single )
7218  else
7219 ! the following code is necessary for using alternate namelist files (nests, stretched grids, etc)
7220  pelist_name = mpp_get_current_pelist_name()
7221  if ( file_exist('input_'//trim(pelist_name)//'.nml', no_domain=.true.) ) then
7222  filename='input_'//trim(pelist_name)//'.nml'
7223  else
7224  filename='input.nml'
7225  endif
7226  call mpp_open ( unit, trim(filename), form=mpp_ascii, action=mpp_rdonly, &
7227  access=mpp_sequential, threading=mpp_single )
7228  endif
7229 end function open_namelist_file
7230 ! </FUNCTION>
7231 
7232 ! <FUNCTION NAME="open_restart_file">
7233 ! <DESCRIPTION>
7234 ! Opens single restart file for reading by all PEs or
7235 ! writing by root PE only
7236 ! the file has native format and no mpp header records.
7237 ! </DESCRIPTION>
7238 !<IN NAME="file" TYPE="character">
7239 ! name of the file to be opened
7240 ! </IN>
7241 !<IN NAME="action" TYPE="character">
7242 ! action to be performed: can be 'read' or 'write'
7243 ! </IN>
7244 ! <OUT NAME="unit" TYPE="integer">
7245 ! unit number returned by this function
7246 ! </OUT>
7247 function open_restart_file (file, action) result (unit)
7248  character(len=*), intent(in) :: file, action
7249  integer :: unit
7250  integer :: mpp_action
7251 
7252  if (.not.module_is_initialized) call fms_io_init ( )
7253 
7254 ! --- action (read,write) ---
7255 
7256  select case (lowercase(trim(action)))
7257  case ('read')
7258  mpp_action = mpp_rdonly
7259  case ('write')
7260  mpp_action = mpp_overwr
7261  case default
7262  call mpp_error(fatal,'fms_io(open_restart_file): action should be either read or write in file'//trim(file))
7263  end select
7264 
7265  call mpp_open ( unit, file, form=mpp_native, action=mpp_action, &
7266  access=mpp_sequential, threading=mpp_single, nohdrs=.true. )
7267 
7268 end function open_restart_file
7269 ! </FUNCTION>
7270 
7271 
7272 ! <FUNCTION NAME="open_direct_file">
7273 ! <DESCRIPTION>
7274 ! Opens single direct access file for reading by all PEs or
7275 ! writing by root PE only
7276 ! the file has native format and no mpp header records.
7277 ! </DESCRIPTION>
7278 
7279  function open_direct_file (file, action, recl) result (unit)
7280  character(len=*), intent(in) :: file, action
7281  integer, intent(in) :: recl
7282  integer :: unit
7283 
7284  integer :: mpp_action
7285 
7286  if (.not.module_is_initialized) call fms_io_init ( )
7287 
7288  ! --- action (read,write) ---
7289 
7290  select case (lowercase(trim(action)))
7291  case ('read')
7292  mpp_action = mpp_rdonly
7293  case ('write')
7294  mpp_action = mpp_overwr
7295  case default
7296  call mpp_error(fatal,'invalid option for argument action')
7297  end select
7298 
7299  call mpp_open ( unit, file, form=mpp_native, action=mpp_action, &
7300  access=mpp_direct, threading=mpp_single, nohdrs=.true., recl=recl )
7301 
7302  end function open_direct_file
7303 ! </FUNCTION>
7304 
7305 ! <FUNCTION NAME=" open_ieee32_file">
7306 ! <DESCRIPTION>
7307 ! Opens single 32-bit ieee file for reading by all PEs or
7308 ! writing by root PE only (writing is not recommended)
7309 ! the file has no mpp header records.
7310 ! </DESCRIPTION>
7311 !<IN NAME="file" TYPE="character">
7312 ! name of the file to be opened
7313 ! </IN>
7314 !<IN NAME="action" TYPE="character">
7315 ! action to be performed: can be 'read' or 'write'
7316 ! </IN>
7317 ! <OUT NAME="unit" TYPE="integer">
7318 ! unit number returned by this function
7319 ! </OUT>
7320 function open_ieee32_file (file, action) result (unit)
7321  character(len=*), intent(in) :: file, action
7322  integer :: unit
7323  integer :: mpp_action
7324 
7325  if (.not.module_is_initialized) call fms_io_init ( )
7326 
7327 ! --- action (read,write) ---
7328  select case (lowercase(trim(action)))
7329  case ('read')
7330  mpp_action = mpp_rdonly
7331  case ('write')
7332  mpp_action = mpp_overwr
7333  case default
7334  call mpp_error (fatal,'fms_io(open_ieee32_file): action should be either read or write in file'//trim(file))
7335  end select
7336 
7337  if (iospec_ieee32(1:1) == ' ') then
7338  call mpp_open ( unit, file, form=mpp_ieee32, action=mpp_action, &
7339  access=mpp_sequential, threading=mpp_single, &
7340  nohdrs=.true. )
7341  else
7342  call mpp_open ( unit, file, form=mpp_ieee32, action=mpp_action, &
7343  access=mpp_sequential, threading=mpp_single, &
7344  nohdrs=.true., iospec=iospec_ieee32 )
7345  endif
7346 end function open_ieee32_file
7347 ! </FUNCTION>
7348 
7349 !#######################################################################
7350 ! <FUNCTION NAME=" close_file">
7351 ! <DESCRIPTION>
7352 ! Closes files that are opened by: open_namelist_file, open restart_file,
7353 ! and open_ieee32_file. Users should use mpp_close for other cases.
7354 ! </DESCRIPTION>
7355 !<IN NAME="unit" TYPE="integer">
7356 ! unit number of the file to be closed
7357 ! </IN>
7358 !<IN NAME="status" TYPE="character, optional">
7359 ! action to be performed: can be 'delete'
7360 ! </IN>
7361 
7362 subroutine close_file (unit, status, dist)
7363  integer, intent(in) :: unit
7364  character(len=*), intent(in), optional :: status
7365  logical, intent(in), optional :: dist
7366 
7367  if (.not.module_is_initialized) call fms_io_init ( )
7368  if(PRESENT(dist))then
7369  ! If distributed, return if not I/O root
7370  if(dist)then
7371  if(.not. mpp_is_dist_ioroot(dr_set_size)) return
7372  endif
7373  endif
7374 
7375  if (unit == stdlog()) return
7376  if (present(status)) then
7377  if (lowercase(trim(status)) == 'delete') then
7378  call mpp_close (unit, action=mpp_delete)
7379  else
7380  call mpp_error(fatal,'fms_io(close_file): status should be DELETE')
7381  endif
7382  else
7383  call mpp_close (unit)
7384  endif
7385 end subroutine close_file
7386 ! </FUNCTION>
7387 
7388 !#######################################################################
7389 
7390 
7391 ! <SUBROUTINE NAME="set_domain">
7392 ! <DESCRIPTION>
7393 ! set_domain is called to save the domain2d data type prior to
7394 ! calling the distributed data I/O routines, read_data and write_data.
7395 ! </DESCRIPTION>
7396 ! <IN NAME="Domain2" TYPE="domain2D">
7397 ! domain to be passed to routines in fms_io_mod, Current_domain will point to
7398 ! this Domain2
7399 ! </IN>
7400 subroutine set_domain (Domain2)
7402  type(domain2d), intent(in), target :: domain2
7403 
7404  if (.NOT.module_is_initialized) call fms_io_init ( )
7405 
7406 ! --- set_domain must be called before a read_data or write_data ---
7407  if (associated(current_domain)) nullify (current_domain)
7408  current_domain => domain2
7409 
7410  ! --- module indexing to shorten read/write routines ---
7411 
7412  call mpp_get_compute_domain (current_domain,is ,ie ,js ,je )
7413  call mpp_get_data_domain (current_domain,isd,ied,jsd,jed)
7414  call mpp_get_global_domain (current_domain,isg,ieg,jsg,jeg)
7415 end subroutine set_domain
7416 !#######################################################################
7417 ! </SUBROUTINE>
7418 
7419 ! <SUBROUTINE NAME="nullify_domain">
7420 subroutine nullify_domain ()
7421 ! <DESCRIPTION>
7422 ! Use to nulify domain that has been assigned by set_domain.
7423 ! </DESCRIPTION>
7424  if (.NOT.module_is_initialized) call fms_io_init ( )
7425 
7426 ! --- set_domain must be called before a read_data or write_data ---
7427 
7428  if (associated(current_domain)) nullify (current_domain)
7429  is=0;ie=0;js=0;je=0
7430  isd=0;ied=0;jsd=0;jed=0
7431  isg=0;ieg=0;jsg=0;jeg=0
7432 end subroutine nullify_domain
7433 ! </SUBROUTINE>
7434 
7435 ! <SUBROUTINE NAME="return_domain">
7436 ! <DESCRIPTION>
7437 ! This routine is the reverse of set_domain above. This routine is called when
7438 ! users want to retrieve the domain2d that is used in fms_io_mod
7439 ! </DESCRIPTION>
7440 ! <OUT NAME="domain2" TYPE="domain2D">
7441 ! domain returned from fms_io_mod.
7442 ! </OUT>
7443 subroutine return_domain(domain2)
7444  type(domain2d), intent(inout) :: domain2
7445 
7446  if (associated(current_domain)) then
7447  domain2 = current_domain
7448  else
7449  domain2 = null_domain2d
7450  endif
7451 end subroutine return_domain
7452 ! </SUBROUTINE>
7453 
7454 !#######################################################################
7455 ! this will be a private routine with the next release
7456 ! users should get the domain decomposition from the domain2d data type
7457 
7458 !#######################################################################
7459 ! <SUBROUTINE NAME="get_domain_decomp">
7460 ! <DESCRIPTION>
7461 ! This will be a private routine with the next release.
7462 ! Users should get the domain decomposition from the domain2d data type.
7463 ! </DESCRIPTION>
7464 ! <OUT NAME="x" TYPE="integer">
7465 ! array containing beginning and ending indices of global and compute domain in x direction
7466 ! </OUT>
7467 ! <OUT NAME="y" TYPE="integer">
7468 ! array containing beginning and ending indices of global and compute domain in y direction
7469 ! </OUT>
7470 subroutine get_domain_decomp ( x, y )
7472  integer, intent(out), dimension(4) :: x, y
7473 
7474  if (mpp_pe() == mpp_root_pe()) call mpp_error(note, &
7475  'subroutine get_domain_decomp will be removed with the next release')
7476  x = (/ isg, ieg, is, ie /)
7477  y = (/ jsg, jeg, js, je /)
7478 
7479 end subroutine get_domain_decomp
7480 ! </SUBROUTINE>
7481 
7482 subroutine get_axis_cart(axis, cart)
7484  type(axistype), intent(in) :: axis
7485  character(len=1), intent(out) :: cart
7486  character(len=1) :: axis_cart
7487  character(len=16), dimension(2) :: lon_names, lat_names
7488  character(len=16), dimension(3) :: z_names
7489  character(len=16), dimension(2) :: t_names
7490  character(len=16), dimension(2) :: lon_units, lat_units
7491  character(len=8) , dimension(4) :: z_units
7492  character(len=3) , dimension(4) :: t_units
7493  character(len=32) :: name
7494  integer :: i
7495 
7496  lon_names = (/'lon','x '/)
7497  lat_names = (/'lat','y '/)
7498  z_names = (/'depth ','height','z '/)
7499  t_names = (/'time','t '/)
7500  lon_units = (/'degrees_e ', 'degrees_east'/)
7501  lat_units = (/'degrees_n ', 'degrees_north'/)
7502  z_units = (/'cm ','m ','pa ','hpa'/)
7503  t_units = (/'sec', 'min','hou','day'/)
7504  call mpp_get_atts(axis,cartesian=axis_cart)
7505  cart = 'N'
7506  if (axis_cart == 'x' ) cart = 'X'
7507  if (axis_cart == 'y' ) cart = 'Y'
7508  if (axis_cart == 'z' ) cart = 'Z'
7509  if (axis_cart == 't' ) cart = 'T'
7510  if (cart /= 'X' .and. cart /= 'Y' .and. cart /= 'Z' .and. cart /= 'T') then
7511  call mpp_get_atts(axis,name=name)
7512  name = lowercase(name)
7513  do i=1,size(lon_names(:))
7514  if (lowercase(name(1:3)) == trim(lon_names(i))) cart = 'X'
7515  enddo
7516  do i=1,size(lat_names(:))
7517  if (name(1:3) == trim(lat_names(i))) cart = 'Y'
7518  enddo
7519  do i=1,size(z_names(:))
7520  if (name == trim(z_names(i))) cart = 'Z'
7521  enddo
7522  do i=1,size(t_names(:))
7523  if (name(1:3) == t_names(i)) cart = 'T'
7524  enddo
7525  end if
7526 
7527  if (cart /= 'X' .and. cart /= 'Y' .and. cart /= 'Z' .and. cart /= 'T') then
7528  call mpp_get_atts(axis,units=name)
7529  name = lowercase(name)
7530  do i=1,size(lon_units(:))
7531  if (trim(name) == trim(lon_units(i))) cart = 'X'
7532  enddo
7533  do i=1,size(lat_units(:))
7534  if (trim(name) == trim(lat_units(i))) cart = 'Y'
7535  enddo
7536  do i=1,size(z_units(:))
7537  if (trim(name) == trim(z_units(i))) cart = 'Z'
7538  enddo
7539  do i=1,size(t_units(:))
7540  if (name(1:3) == trim(t_units(i))) cart = 'T'
7541  enddo
7542  end if
7543 
7544  return
7545 end subroutine get_axis_cart
7546 
7547 ! The following function is here as a last resort.
7548 ! This is copied from what was utilities_mod in order that redundant code
7549 ! could be deleted.
7550 
7551 function open_file(file, form, action, access, threading, recl, dist) result(unit)
7553  character(len=*), intent(in) :: file
7554  character(len=*), intent(in), optional :: form, action, access, threading
7555  integer , intent(in), optional :: recl
7556  logical , intent(in), optional :: dist ! Distributed open?
7557  integer :: unit
7558 
7559  character(len=32) :: form_local, action_local, access_local, thread_local
7560  character(len=32) :: action_ieee32
7561  logical :: open, no_headers, do_ieee32
7562  integer :: mpp_format, mpp_action, mpp_access, mpp_thread
7563 !-----------------------------------------------------------------------
7564 
7565  if ( .not. module_is_initialized ) call fms_io_init ( )
7566 
7567  if (present(action)) then ! must be present
7568  action_local = action
7569  else
7570  call mpp_error (fatal, 'open_file in fms_mod : argument action not present')
7571  endif
7572 
7573  unit = 0 ! Initialize return value. Note that mpp_open will call mpi_abort on error
7574  if(PRESENT(dist))then
7575  if(lowercase(trim(action_local)) /= 'read') &
7576  call mpp_error(fatal,'open_file in fms_mod: distributed'//lowercase(trim(action_local))// &
7577  ' not currently supported')
7578  ! If distributed, return if not I/O root
7579  if(dist) then
7580  if(.not. mpp_is_dist_ioroot(dr_set_size)) return
7581  endif
7582  endif
7583 
7584 ! ---- return stdlog if this is the logfile ----
7585 
7586  if (trim(file) == 'logfile.out') then
7587  unit = stdlog()
7588  return
7589  endif
7590 
7591 ! ---- is this file open and connected to a unit ?? ----
7592 
7593  inquire (file=trim(file), opened=open, number=unit)
7594 
7595 ! cannot open a file that is already open
7596 ! except for the log file
7597 
7598  if ( open .and. unit >= 0 ) then
7599  call mpp_error (fatal, 'open_file in fms_mod : '// &
7600  'file '//trim(file)//' is already open')
7601  endif
7602 
7603 ! --- defaults ---
7604 
7605  form_local = 'formatted'; if (present(form)) form_local = form
7606  access_local = 'sequential'; if (present(access)) access_local = access
7607  thread_local = 'single'; if (present(threading)) thread_local = threading
7608  no_headers = .true.
7609  do_ieee32 = .false.
7610 
7611 ! --- file format ---
7612 
7613  select case (lowercase(trim(form_local)))
7614  case ('formatted')
7615  mpp_format = mpp_ascii
7616  case ('ascii')
7617  mpp_format = mpp_ascii
7618  case ('unformatted')
7619  mpp_format = mpp_native
7620  case ('native')
7621  mpp_format = mpp_native
7622  case ('ieee32')
7623  do_ieee32 = .true.
7624  case ('netcdf')
7625  mpp_format = mpp_netcdf
7626  case default
7627  call mpp_error (fatal, 'open_file in fms_mod : '// &
7628  'invalid option for argument form')
7629  end select
7630 
7631 ! --- action (read,write,append) ---
7632 
7633  select case (lowercase(trim(action_local)))
7634  case ('read')
7635  mpp_action = mpp_rdonly
7636  case ('write')
7637  mpp_action = mpp_overwr
7638  case ('append')
7639  mpp_action = mpp_append
7640  case default
7641  call mpp_error (fatal, 'open_file in fms_mod : '// &
7642  'invalid option for argument action')
7643  end select
7644 
7645 ! --- file access (sequential,direct) ---
7646 
7647  select case (lowercase(trim(access_local)))
7648  case ('sequential')
7649  mpp_access = mpp_sequential
7650  case ('direct')
7651  mpp_access = mpp_direct
7652  case default
7653  call mpp_error (fatal, 'open_file in fms_mod : '// &
7654  'invalid option for argument access')
7655  end select
7656 
7657 ! --- threading (single,multi) ---
7658 
7659  select case (lowercase(trim(thread_local)))
7660  case ('single')
7661  mpp_thread = mpp_single
7662  case ('multi')
7663  mpp_thread = mpp_multi
7664  case default
7665  call mpp_error (fatal, 'open_file in fms_mod : '// &
7666  'invalid option for argument thread')
7667  if (trim(file) /= '_read_error.nml') no_headers = .false.
7668  end select
7669 
7670 ! ---------------- open file -----------------------
7671 
7672  if ( .not.do_ieee32 ) then
7673  call mpp_open ( unit, file, form=mpp_format, action=mpp_action, &
7674  access=mpp_access, threading=mpp_thread, &
7675  fileset=mpp_single,nohdrs=no_headers, recl=recl )
7676  else
7677  ! special open for ieee32 file
7678  ! fms_mod has iospec value
7679  ! pass local action flag to open changing append to write
7680  action_ieee32 = action_local
7681  if (lowercase(trim(action_ieee32)) == 'append') action_ieee32 = 'write'
7682  unit = open_ieee32_file( file, action_ieee32 )
7683  endif
7684 
7685 !-----------------------------------------------------------------------
7686 
7687  end function open_file
7688 
7689  !#######################################################################
7690 
7691  function string_from_integer(n)
7692  integer, intent(in) :: n
7693  character(len=16) :: string_from_integer
7694 
7695  if(n<0) then
7696  call mpp_error(fatal, 'fms_io_mod: n should be non-negative integer, contact developer')
7697  else if( n<10 ) then
7698  write(string_from_integer,'(i1)') n
7699  else if( n<100 ) then
7700  write(string_from_integer,'(i2)') n
7701  else if( n<1000 ) then
7702  write(string_from_integer,'(i3)') n
7703  else if( n<10000 ) then
7704  write(string_from_integer,'(i4)') n
7705  else if( n<100000 ) then
7706  write(string_from_integer,'(i5)') n
7707  else if( n<1000000 ) then
7708  write(string_from_integer,'(i6)') n
7709  else if( n<10000000 ) then
7710  write(string_from_integer,'(i7)') n
7711  else if( n<100000000 ) then
7712  write(string_from_integer,'(i8)') n
7713  else
7714  call mpp_error(fatal, 'fms_io_mod: n is too big, contact developer')
7715  end if
7716 
7717  return
7718 
7719  end function string_from_integer
7720 
7721  !#######################################################################
7722  function string_from_real(a)
7723  real, intent(in) :: a
7724  character(len=32) :: string_from_real
7725 
7726  write(string_from_real,*) a
7727 
7728  return
7729 
7730  end function string_from_real
7731 
7732  !#######################################################################
7733 
7734  subroutine get_tile_string(str_out, str_in, tile, str2_in)
7735  character(len=*), intent(inout) :: str_out
7736  character(len=*), intent(in) :: str_in
7737  integer, intent(in) :: tile
7738  character(len=*), intent(in), optional :: str2_in
7739 
7740  if(tile > 0 .AND. tile < 9) then
7741  write(str_out,'(a,i1)') trim(str_in), tile
7742  else if(tile >= 10 .AND. tile < 99) then
7743  write(str_out,'(a,i2)') trim(str_in), tile
7744  else
7745  call mpp_error(fatal, "FMS_IO: get_tile_string: tile must be a positive number less than 100")
7746  end if
7747 
7748  if(present(str2_in)) str_out=trim(str_out)//trim(str2_in)
7749 
7750  end subroutine get_tile_string
7751 
7752 
7753  !#####################################################################
7754  subroutine get_mosaic_tile_file_sg(file_in, file_out, is_no_domain, domain, tile_count)
7755  character(len=*), intent(in) :: file_in
7756  character(len=*), intent(out) :: file_out
7757  logical, intent(in) :: is_no_domain
7758  type(domain2D), intent(in), optional, target :: domain
7759  integer, intent(in), optional :: tile_count
7760  character(len=256) :: basefile, tilename
7761  integer :: lens, ntiles, ntileMe, tile, my_tile_id
7762  integer, dimension(:), allocatable :: tile_id
7763  type(domain2d), pointer, save :: d_ptr =>null()
7764  logical :: domain_exist
7765 
7766  if(index(file_in, '.nc', back=.true.)==0) then
7767  basefile = trim(file_in)
7768  else
7769  lens = len_trim(file_in)
7770  if(file_in(lens-2:lens) .NE. '.nc') call mpp_error(fatal, &
7771  'fms_io_mod: .nc should be at the end of file '//trim(file_in))
7772  basefile = file_in(1:lens-3)
7773  end if
7774 
7775  !--- get the tile name
7776  ntiles = 1
7777  my_tile_id = 1
7778  domain_exist = .false.
7779  if(PRESENT(domain))then
7780  domain_exist = .true.
7781  ntiles = mpp_get_ntile_count(domain)
7782  d_ptr => domain
7783  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
7784  domain_exist = .true.
7785  ntiles = mpp_get_ntile_count(current_domain)
7786  d_ptr => current_domain
7787  endif
7788 
7789  if(domain_exist) then
7790  ntileme = mpp_get_current_ntile(d_ptr)
7791  allocate(tile_id(ntileme))
7792  tile_id = mpp_get_tile_id(d_ptr)
7793  tile = 1
7794  if(present(tile_count)) tile = tile_count
7795  my_tile_id = tile_id(tile)
7796  endif
7797 
7798  if(ntiles > 1 .or. my_tile_id > 1 )then
7799  tilename = 'tile'//string(my_tile_id)
7800  if(index(basefile,'.'//trim(tilename),back=.true.) == 0)then
7801  basefile = trim(basefile)//'.'//trim(tilename);
7802  end if
7803  end if
7804  if(allocated(tile_id)) deallocate(tile_id)
7805 
7806  file_out = trim(basefile)//'.nc'
7807 
7808  d_ptr =>null()
7809 
7810  end subroutine get_mosaic_tile_file_sg
7811 
7812  subroutine get_mosaic_tile_file_ug(file_in, file_out, domain)
7813  character(len=*), intent(in) :: file_in
7814  character(len=*), intent(out) :: file_out
7815  type(domainug), intent(in), optional :: domain
7816  character(len=256) :: basefile, tilename
7817  integer :: lens, ntiles, my_tile_id
7818 
7819  if(index(file_in, '.nc', back=.true.)==0) then
7820  basefile = trim(file_in)
7821  else
7822  lens = len_trim(file_in)
7823  if(file_in(lens-2:lens) .NE. '.nc') call mpp_error(fatal, &
7824  'fms_io_mod: .nc should be at the end of file '//trim(file_in))
7825  basefile = file_in(1:lens-3)
7826  end if
7827 
7828  !--- get the tile name
7829  ntiles = 1
7830  my_tile_id = 1
7831  if(PRESENT(domain))then
7832  ntiles = mpp_get_ug_domain_ntiles(domain)
7833  my_tile_id = mpp_get_ug_domain_tile_id(domain)
7834  endif
7835 
7836  if(ntiles > 1 .or. my_tile_id > 1 )then
7837  tilename = 'tile'//string(my_tile_id)
7838  if(index(basefile,'.'//trim(tilename),back=.true.) == 0)then
7839  basefile = trim(basefile)//'.'//trim(tilename);
7840  end if
7841  end if
7842 
7843  file_out = trim(basefile)//'.nc'
7844 
7845  end subroutine get_mosaic_tile_file_ug
7846 
7847 
7848  !#############################################################################
7849  subroutine get_mosaic_tile_grid(grid_file, mosaic_file, domain, tile_count)
7850  character(len=*), intent(out) :: grid_file
7851  character(len=*), intent(in) :: mosaic_file
7852  type(domain2d), intent(in) :: domain
7853  integer, intent(in), optional :: tile_count
7854  integer :: tile, ntileme
7855  integer, dimension(:), allocatable :: tile_id
7856 
7857  tile = 1
7858  if(present(tile_count)) tile = tile_count
7859  ntileme = mpp_get_current_ntile(domain)
7860  allocate(tile_id(ntileme))
7861  tile_id = mpp_get_tile_id(domain)
7862  call read_data(mosaic_file, "gridfiles", grid_file, level=tile_id(tile) )
7863  grid_file = 'INPUT/'//trim(grid_file)
7864  deallocate(tile_id)
7865 
7866  end subroutine get_mosaic_tile_grid
7867 
7868  subroutine get_var_att_value_text(file, varname, attname, attvalue)
7869  character(len=*), intent(in) :: file
7870  character(len=*), intent(in) :: varname
7871  character(len=*), intent(in) :: attname
7872  character(len=*), intent(inout) :: attvalue
7873  integer :: unit
7874 
7875  call mpp_open(unit,trim(file),mpp_rdonly,mpp_netcdf,threading=mpp_multi,fileset=mpp_single)
7876  call mpp_get_att_value(unit, varname, attname, attvalue)
7877  call mpp_close(unit)
7878 
7879  return
7880 
7881  end subroutine get_var_att_value_text
7882 
7883  !#############################################################################
7884  ! return false if the attribute is not found in the file.
7885  function get_global_att_value_text(file, att, attvalue)
7886  character(len=*), intent(in) :: file
7887  character(len=*), intent(in) :: att
7888  character(len=*), intent(inout) :: attvalue
7889  logical :: get_global_att_value_text
7890  integer :: unit, ndim, nvar, natt, ntime, i
7891  type(atttype), allocatable :: global_atts(:)
7892 
7893  get_global_att_value_text = .false.
7894  call mpp_open(unit,trim(file),mpp_rdonly,mpp_netcdf,threading=mpp_multi,fileset=mpp_single)
7895  call mpp_get_info(unit, ndim, nvar, natt, ntime)
7896  allocate(global_atts(natt))
7897  call mpp_get_atts(unit,global_atts)
7898  do i=1,natt
7899  if( trim(mpp_get_att_name(global_atts(i))) == trim(att) ) then
7900  attvalue = trim(mpp_get_att_char(global_atts(i)))
7901  get_global_att_value_text = .true.
7902  exit
7903  end if
7904  end do
7905  deallocate(global_atts)
7906 
7907  return
7908 
7909  end function get_global_att_value_text
7910 
7911  !#############################################################################
7912  ! return false if the attribute is not found in the file.
7913  function get_global_att_value_real(file, att, attvalue)
7914  character(len=*), intent(in) :: file
7915  character(len=*), intent(in) :: att
7916  real, intent(inout) :: attvalue
7917  logical :: get_global_att_value_real
7918  integer :: unit, ndim, nvar, natt, ntime, i
7919  type(atttype), allocatable :: global_atts(:)
7920 
7921  get_global_att_value_real = .false.
7922  call mpp_open(unit,trim(file),mpp_rdonly,mpp_netcdf,threading=mpp_multi,fileset=mpp_single)
7923  call mpp_get_info(unit, ndim, nvar, natt, ntime)
7924  allocate(global_atts(natt))
7925  call mpp_get_atts(unit,global_atts)
7926  do i=1,natt
7927  if( trim(mpp_get_att_name(global_atts(i))) == trim(att) ) then
7928  attvalue = mpp_get_att_real_scalar(global_atts(i))
7929  get_global_att_value_real = .true.
7930  exit
7931  end if
7932  end do
7933  deallocate(global_atts)
7934 
7935  return
7936 
7937  end function get_global_att_value_real
7938 
7939  !#############################################################################
7940  ! This routine will get the actual file name, as well as if read_dist is true or false.
7941  ! return true if such file exist and return false if not.
7942  function get_file_name(orig_file, actual_file, read_dist, io_domain_exist, no_domain, domain, &
7943  tile_count)
7944  character(len=*), intent(in) :: orig_file
7945  character(len=*), intent(out) :: actual_file
7946  logical, intent(out) :: read_dist
7947  logical, intent(out) :: io_domain_exist
7948  logical, optional, intent(in) :: no_domain
7949  type(domain2d), target, optional, intent(in) :: domain
7950  integer, optional, intent(in) :: tile_count
7951  logical :: get_file_name
7952 
7953  type(domain2d), pointer, save :: d_ptr, io_domain
7954  logical :: fexist, is_no_domain
7955  integer :: tile_id(1)
7956  character(len=256) :: fname
7957  character(len=512) :: actual_file_tmp
7958 
7959  is_no_domain=.false.
7960  if(PRESENT(no_domain)) is_no_domain = no_domain
7961 
7962 
7963  fexist = .false.
7964  read_dist = .false.
7965  get_file_name = .false.
7966  io_domain_exist = .false.
7967 
7968  !--- The file maybe not netcdf file, we just check the original file.
7969  if(index(orig_file, '.nc', back=.true.) == 0) then
7970  inquire (file=trim(orig_file), exist=fexist)
7971  if(fexist) then
7972  actual_file = orig_file
7973  get_file_name = .true.
7974  return
7975  endif
7976  endif
7977 
7978  if(present(domain)) then
7979  d_ptr => domain
7980  elseif (ASSOCIATED(current_domain) .AND. .NOT. is_no_domain ) then
7981  d_ptr => current_domain
7982  endif
7983 
7984 
7985  !JWD: This is likely a temporary fix. Since fms_io needs to know tile_count,
7986  !JWD: I just don't see how the physics can remain "tile neutral"
7987  call get_mosaic_tile_file(orig_file, actual_file, is_no_domain, domain, tile_count)
7988 
7989  !--- check if the file is group redistribution.
7990  if(ASSOCIATED(d_ptr)) then
7991  io_domain => mpp_get_io_domain(d_ptr)
7992  if(associated(io_domain)) then
7993  tile_id = mpp_get_tile_id(io_domain)
7994  write(fname, '(a,i4.4)' ) trim(actual_file)//'.', tile_id(1)
7995  inquire (file=trim(fname), exist=fexist)
7996  if(.not. fexist) then
7997  write(fname, '(a,i6.6)' ) trim(actual_file)//'.', tile_id(1)
7998  inquire (file=trim(fname), exist=fexist)
7999  endif
8000  if(fexist) io_domain_exist = .true.
8001  endif
8002  io_domain=>null()
8003  endif
8004 
8005  if(fexist) then
8006  read_dist = .true.
8007  d_ptr => null()
8008  get_file_name = .true.
8009  return
8010  endif
8011 
8012  inquire (file=trim(actual_file), exist=fexist)
8013  if(fexist) then
8014  d_ptr => null()
8015  get_file_name = .true.
8016  return
8017  endif
8018 
8019  !Perhaps the file has an ensemble instance appendix
8020  if(len_trim(filename_appendix) > 0) then
8021  call get_instance_filename(orig_file, actual_file)
8022  if(index(orig_file, '.nc', back=.true.) == 0) then
8023  inquire (file=trim(actual_file), exist=fexist)
8024  if(fexist) then
8025  d_ptr => null()
8026  get_file_name = .true.
8027  return
8028  endif
8029  endif
8030 
8031  ! Set actual_file to tmp for passing to get_mosaic_tile_file
8032  actual_file_tmp = actual_file
8033  call get_mosaic_tile_file(actual_file_tmp, actual_file, is_no_domain, domain, tile_count)
8034 
8035  !--- check if the file is group redistribution.
8036  if(ASSOCIATED(d_ptr)) then
8037  io_domain => mpp_get_io_domain(d_ptr)
8038  if(associated(io_domain)) then
8039  tile_id = mpp_get_tile_id(io_domain)
8040  if(mpp_npes()>10000) then
8041  write(fname, '(a,i6.6)' ) trim(actual_file)//'.', tile_id(1)
8042  else
8043  write(fname, '(a,i4.4)' ) trim(actual_file)//'.', tile_id(1)
8044  endif
8045  inquire (file=trim(fname), exist=fexist)
8046  if(fexist) io_domain_exist = .true.
8047  endif
8048  io_domain=>null()
8049  endif
8050 
8051  if(fexist) then
8052  read_dist = .true.
8053  d_ptr => null()
8054  get_file_name = .true.
8055  return
8056  endif
8057 
8058  inquire (file=trim(actual_file), exist=fexist)
8059 
8060  if(fexist) then
8061  d_ptr => null()
8062  get_file_name = .true.
8063  return
8064  endif
8065  endif
8066 
8067  end function get_file_name
8068 
8069 
8070  !#############################################################################
8071  subroutine get_file_unit(filename, unit, index_file, read_dist, io_domain_exist, domain )
8072  character(len=*), intent(in) :: filename
8073  integer, intent(out) :: unit, index_file
8074  logical, intent(in) :: read_dist, io_domain_exist
8075  type(domain2d), optional, intent(in) :: domain
8076 
8077  logical :: file_opened
8078  integer :: i
8079 
8080  ! Need to check if filename has been opened or not
8081  file_opened=.false.
8082  do i=1,num_files_r
8083  if (files_read(i)%name == trim(filename)) then
8084  index_file = i
8085  unit = files_read(index_file)%unit
8086  return
8087  endif
8088  enddo
8089 
8090  ! need to open the file now
8091  ! Increase num_files_r and set file_type
8092  if(num_files_r == max_files_r) & ! need to have bigger max_files_r
8093  call mpp_error(fatal,'fms_io(get_file_unit): max_files_r exceeded, increase it via fms_io_nml')
8095  if(read_dist) then
8096  if(io_domain_exist) then
8097  if(present(domain)) then
8098  call mpp_open(unit,filename,form=form,action=mpp_rdonly,threading=mpp_multi, &
8099  fileset=mpp_multi, domain=domain)
8100  else if(ASSOCIATED(current_domain) ) then
8101  call mpp_open(unit,filename,form=form,action=mpp_rdonly,threading=mpp_multi, &
8102  fileset=mpp_multi, domain=current_domain)
8103  else
8104  call mpp_error(fatal,'fms_io(get_file_unit): when io_domain_exsit = .true., '// &
8105  'either domain is present or current_domain is associated')
8106  endif
8107  else
8108  call mpp_open(unit,trim(filename),form=form,action=mpp_rdonly,threading=mpp_multi, &
8109  fileset=mpp_multi)
8110  endif
8111  else
8112  call mpp_open(unit,trim(filename),form=form,action=mpp_rdonly,threading=mpp_multi, &
8113  fileset=mpp_single)
8114  end if
8115  files_read(num_files_r)%name = trim(filename)
8116  allocate(files_read(num_files_r)%var (max_fields) )
8117  files_read(num_files_r)%nvar = 0
8118  index_file = num_files_r
8119  files_read(index_file)%unit = unit
8120 
8121  end subroutine get_file_unit
8122 
8123  !#############################################################################
8124  subroutine get_field_id(unit, index_file, fieldname, index_field, is_no_domain, is_not_dim)
8125  integer, intent(in) :: unit
8126  integer, intent(in) :: index_file
8127  character(len=*), intent(in) :: fieldname
8128  integer, intent(out) :: index_field
8129  logical, intent(in) :: is_no_domain
8130  logical, intent(in) :: is_not_dim
8131 
8132  character(len=128) :: name
8133  type(axistype), dimension(max_axes) :: axes
8134  type(fieldtype), dimension(max_fields) :: fields
8135  integer :: i, j, ndim, nvar, natt, var_dim
8136  integer :: siz_in(4)
8137 
8138  index_field = -1
8139  do j = 1, files_read(index_file)%nvar
8140  if (trim(files_read(index_file)%var(j)%name) == trim(fieldname)) then
8141  index_field = j
8142  return
8143  endif
8144  enddo
8145 
8146  !--- fieldname is not read, so need to get fieldname from file
8147  files_read(index_file)%nvar = files_read(index_file)%nvar + 1
8148  if(files_read(index_file)%nvar > max_fields) then
8149  write(error_msg,'(I3,"/",I3)') files_read(index_file)%nvar, max_fields
8150  call mpp_error(fatal,'fms_io(get_field_id): max_fields exceeded, needs increasing, nvar/max_fields=' &
8151  //trim(error_msg))
8152  endif
8153  call mpp_get_info(unit, ndim, nvar, natt, files_read(index_file)%max_ntime)
8154  if(files_read(index_file)%max_ntime < 1) files_read(index_file)%max_ntime = 1
8155  if(nvar > max_fields) then
8156  write(error_msg,'(I3,"/",I3)') files_read(index_file)%nvar,max_fields
8157  call mpp_error(fatal,'fms_io(get_field_id): max_fields too small needs increasing,nvar/max_fields=' &
8158  //trim(error_msg)//'in file'//trim(files_read(index_file)%name))
8159  endif
8160  call mpp_get_fields(unit, fields(1:nvar))
8161  siz_in = 1
8162  index_field = files_read(index_file)%nvar
8163  files_read(index_file)%var(index_field)%is_dimvar = .false.
8164 
8165  do i=1, nvar
8166  call mpp_get_atts(fields(i),name=name,ndim=var_dim,siz=siz_in)
8167  if(var_dim .GT. 4) call mpp_error(fatal, 'fms_io(get_field_id): number of dimension of field '// &
8168  trim(name)//' in file '//trim(files_read(index_file)%name)//' should not be greater than 4')
8169  if (lowercase(trim(name)) == lowercase(trim(fieldname))) then ! found the variable
8170  if(var_dim .lt.3) then
8171  do j=var_dim+1,3
8172  siz_in(j)=1
8173  enddo
8174  endif
8175  files_read(index_file)%var(index_field)%name = fieldname
8176  files_read(index_file)%var(index_field)%field = fields(i)
8177  files_read(index_file)%var(index_field)%siz(1:4) = siz_in(1:4)
8178  files_read(index_file)%var(index_field)%gsiz(1:3) = siz_in(1:3)
8179  return
8180  endif
8181  enddo
8182 
8183  !--- the fieldname may be a dimension variable.
8184  if( .not. is_not_dim) then
8185  if (ndim > max_axes) then
8186  write(error_msg,'(I3,"/",I3)') ndim, max_axes
8187  call mpp_error(fatal,'fms_io(get_field_id): max_axes exceeded, needs increasing, ndim/max_fields=' &
8188  //trim(error_msg)//' in file '//trim(files_read(index_file)%name))
8189  endif
8190  call mpp_get_axes(unit, axes(1:ndim))
8191  do i=1,ndim
8192  call mpp_get_atts(axes(i), name=name, len = siz_in(1))
8193  if (lowercase(trim(name)) == lowercase(trim(fieldname))) then
8194 ! if(.not. is_no_domain) call mpp_error(FATAL, &
8195 ! 'fms_io(get_field_id): the field is a dimension variable, no_domain should be true.')
8196  files_read(index_file)%var(index_field)%is_dimvar = .true.
8197  files_read(index_file)%var(index_field)%name = fieldname
8198  files_read(index_file)%var(index_field)%axis = axes(i)
8199  files_read(index_file)%var(index_field)%siz(1:4) = siz_in(1:4)
8200  files_read(index_file)%var(index_field)%gsiz(1:3) = siz_in(1:3)
8201  return
8202  endif
8203  enddo
8204  end if
8205  !--- the field is not in the file when reaching here.
8206  call mpp_error(fatal, 'fms_io(get_field_id): field '//trim(fieldname)// &
8207  ' NOT found in file '//trim(files_read(index_file)%name))
8208 
8209  end subroutine get_field_id
8210 
8211 !#######################################################################
8212 ! check the existence of the given file name
8213 ! if the file_name string has zero length or the
8214 ! first character is blank return a false result
8215 ! <FUNCTION NAME="file_exist">
8216 
8217 ! <OVERVIEW>
8218 ! Checks the existence of a given file name.
8219 ! </OVERVIEW>
8220 ! <DESCRIPTION>
8221 ! Checks the existence of the given file name.
8222 ! If the file_name string has zero length or the
8223 ! first character is blank return a false result.
8224 ! </DESCRIPTION>
8225 ! <TEMPLATE>
8226 ! file_exist ( file_name )
8227 ! </TEMPLATE>
8228 
8229 ! <IN NAME="file_name" TYPE="character" >
8230 ! A file name (or path name) that is checked for existence.
8231 ! </IN>
8232 ! <OUT NAME="" TYPE="logical" >
8233 ! This function returns a logical result. If file_name exists the result
8234 ! is true, otherwise false is returned.
8235 ! If the length of character string "file_name" is zero or the first
8236 ! character is blank, then the returned value will be false.
8237 ! When reading a file, this function is often used in conjunction with
8238 ! routine open_file.
8239 ! </OUT>
8240 ! <ERROR MSG="set_domain not called" STATUS="FATAL">
8241 ! Before calling write_data you must first call set_domain with domain2d data
8242 ! type associated with the distributed data you are writing.
8243 ! </ERROR>
8244 
8245  function file_exist (file_name, domain, no_domain)
8246  character(len=*), intent(in) :: file_name
8247  type(domain2d), intent(in), optional :: domain
8248  logical, intent(iN), optional :: no_domain
8249 
8250  logical :: file_exist, is_no_domain
8251  character(len=256) :: fname
8252  logical :: read_dist, io_domain_exist
8253 
8254  is_no_domain = .false.
8255  if(present(no_domain)) is_no_domain = no_domain
8256  !--- to deal with mosaic file, in this case, the file is assumed to be in netcdf format
8257  file_exist = get_file_name(file_name, fname, read_dist, io_domain_exist, no_domain=is_no_domain, domain=domain)
8258  if(is_no_domain) return
8259  if(.not.file_exist) file_exist=get_file_name(file_name, fname, read_dist, io_domain_exist, no_domain=.true.)
8260 
8261  return
8262 
8263  end function file_exist
8264 ! </FUNCTION>
8265 
8266 
8267 !#######################################################################
8268 ! <FUNCTION NAME="field_exist">
8269 
8270 ! <OVERVIEW>
8271 ! check if a given field name exists in a given file name.
8272 ! </OVERVIEW>
8273 ! <DESCRIPTION>
8274 ! check if a given field name exists in a given file name.
8275 ! If the field_name string has zero length or the
8276 ! first character is blank return a false result.
8277 ! if the file file_name don't exist, return a false result.
8278 ! </DESCRIPTION>
8279 ! <TEMPLATE>
8280 ! field_exist ( file_name, field_name )
8281 ! </TEMPLATE>
8282 
8283 ! <IN NAME="file_name" TYPE="character" >
8284 ! A file name (or path name) that is checked for existence.
8285 ! </IN>
8286 ! <IN NAME="field_name" TYPE="character" >
8287 ! A field name that is checked for existence.
8288 ! </IN>
8289 ! <OUT NAME="" TYPE="logical" >
8290 ! This function returns a logical result. If field exists in the
8291 ! file file_name, the result is true, otherwise false is returned.
8292 ! If the length of character string "field_name" is zero or the first
8293 ! character is blank, then the returned value will be false.
8294 ! if the file file_name don't exist, return a false result.
8295 ! </OUT>
8296 
8297  function field_exist (file_name, field_name, domain, no_domain)
8298  character(len=*), intent(in) :: file_name
8299  character(len=*), intent(in) :: field_name
8300  type(domain2d), intent(in), optional, target :: domain
8301  logical, intent(in), optional :: no_domain
8302  logical :: field_exist, is_no_domain
8303  integer :: unit, ndim, nvar, natt, ntime, i, nfile
8304  character(len=64) :: name
8305  type(fieldtype), allocatable :: fields(:)
8306  logical :: file_exist, read_dist, io_domain_exist
8307  character(len=256) :: fname
8308 
8309  field_exist = .false.
8310  if (len_trim(field_name) == 0) return
8311  if (field_name(1:1) == ' ') return
8312 
8313  is_no_domain = .false.
8314  if(present(no_domain)) is_no_domain = no_domain
8315 
8316  file_exist=get_file_name(file_name, fname, read_dist, io_domain_exist, no_domain=is_no_domain, domain=domain)
8317  if(file_exist) then
8318  call get_file_unit(fname, unit, nfile, read_dist, io_domain_exist, domain=domain)
8319  call mpp_get_info(unit, ndim, nvar, natt, ntime)
8320  allocate(fields(nvar))
8321  call mpp_get_fields(unit,fields)
8322 
8323  do i=1, nvar
8324  call mpp_get_atts(fields(i),name=name)
8325  if(lowercase(trim(name)) == lowercase(trim(field_name))) field_exist = .true.
8326  enddo
8327  deallocate(fields)
8328  endif
8329  if(field_exist .or. is_no_domain) return
8330  file_exist = get_file_name(file_name, fname, read_dist, io_domain_exist, no_domain=.true.)
8331  if(file_exist) then
8332  call get_file_unit(fname, unit, nfile, read_dist, io_domain_exist)
8333  call mpp_get_info(unit, ndim, nvar, natt, ntime)
8334  allocate(fields(nvar))
8335  call mpp_get_fields(unit,fields)
8336  do i=1, nvar
8337  call mpp_get_atts(fields(i),name=name)
8338  if(lowercase(trim(name)) == lowercase(trim(field_name))) field_exist = .true.
8339  enddo
8340  deallocate(fields)
8341  endif
8342 
8343  return
8344 
8345  end function field_exist
8346 ! </FUNCTION>
8347 
8348 
8349 subroutine get_filename_appendix(string_out)
8350  character(len=*) , intent(out) :: string_out
8351 
8352  string_out = trim(filename_appendix)
8353 
8354 
8355 end subroutine get_filename_appendix
8356 
8357 
8358 subroutine nullify_filename_appendix()
8360  filename_appendix = ''
8361 
8362 end subroutine nullify_filename_appendix
8363 
8364 
8365 subroutine set_filename_appendix(string_in)
8366  character(len=*) , intent(in) :: string_in
8367 
8368  integer :: index_num
8369 
8370  ! Check if string has already been added
8371  index_num = index(filename_appendix, string_in)
8372  if ( index_num .le. 0 ) then
8373  filename_appendix = trim(filename_appendix)//trim(string_in)
8374  end if
8375 
8376 end subroutine set_filename_appendix
8377 
8378 subroutine get_instance_filename(name_in,name_out)
8379  character(len=*) , intent(in) :: name_in
8380  character(len=*), intent(inout) :: name_out
8381  integer :: length
8382 
8383  length = len_trim(name_in)
8384  name_out = name_in(1:length)
8385 
8386  if(len_trim(filename_appendix) > 0) then
8387  if(name_in(length-2:length) == '.nc') then
8388  name_out = name_in(1:length-3)//'.'//trim(filename_appendix)//'.nc'
8389  else
8390  name_out = name_in(1:length) //'.'//trim(filename_appendix)
8391  end if
8392  end if
8393 
8394 end subroutine get_instance_filename
8395 
8396 !#######################################################################
8397 subroutine parse_mask_table_2d(mask_table, maskmap, modelname)
8399  character(len=*), intent(in) :: mask_table
8400  logical, intent(out) :: maskmap(:,:)
8401  character(len=*), intent(in) :: modelname
8402  integer :: nmask, layout(2)
8403  integer, allocatable :: mask_list(:,:)
8404  integer :: unit, mystat, n, stdoutunit
8405  character(len=128) :: record
8406 
8407  maskmap = .true.
8408  nmask = 0
8409  stdoutunit = stdout()
8410  if( mpp_pe() == mpp_root_pe() ) then
8411  call mpp_open(unit, mask_table, action=mpp_rdonly)
8412  read(unit, fmt=*, iostat=mystat) nmask
8413  if( mystat /= 0 ) call mpp_error(fatal, &
8414  "fms_io(parse_mask_table_2d): Error reading nmask from file " //trim(mask_table))
8415  write(stdoutunit,*)"parse_mask_table: Number of domain regions masked in ", trim(modelname), " = ", nmask
8416  if( nmask > 0 ) then
8417  !--- read layout from mask_table and confirm it matches the shape of maskmap
8418  read(unit, fmt=*, iostat=mystat) layout
8419  if( mystat /= 0 ) call mpp_error(fatal, &
8420  "fms_io(parse_mask_talbe_2d): Error reading layout from file " //trim(mask_table))
8421  if( (layout(1) .NE. size(maskmap,1)) .OR. (layout(2) .NE. size(maskmap,2)) )then
8422  write(stdoutunit,*)"layout=", layout, ", size(maskmap) = ", size(maskmap,1), size(maskmap,2)
8423  call mpp_error(fatal, "fms_io(parse_mask_table_2d): layout in file "//trim(mask_table)// &
8424  "does not match size of maskmap for "//trim(modelname))
8425  endif
8426  !--- make sure mpp_npes() == layout(1)*layout(2) - nmask
8427  if( mpp_npes() .NE. layout(1)*layout(2) - nmask ) call mpp_error(fatal, &
8428  .NE."fms_io(parse_mask_table_2d): mpp_npes() layout(1)*layout(2) - nmask for "//trim(modelname))
8429  endif
8430  endif
8431 
8432  call mpp_broadcast(nmask, mpp_root_pe())
8433 
8434  if(nmask==0) then
8435  if( mpp_pe() == mpp_root_pe() ) call mpp_close(unit)
8436  return
8437  endif
8438 
8439  allocate(mask_list(nmask,2))
8440 
8441  if( mpp_pe() == mpp_root_pe() ) then
8442  n = 0
8443  do while( .true. )
8444  read(unit,'(a)',end=999) record
8445  if (record(1:1) == '#') cycle
8446  if (record(1:10) == ' ') cycle
8447  n = n + 1
8448  if( n > nmask ) then
8449  call mpp_error(fatal, "fms_io(parse_mask_table_2d): number of mask_list entry "// &
8450  "is greater than nmask in file "//trim(mask_table) )
8451  endif
8452  read(record,*,err=888) mask_list(n,1), mask_list(n,2)
8453  enddo
8454 888 call mpp_error(fatal, "fms_io(parse_mask_table_2d): Error in reading mask_list from file "//trim(mask_table))
8455 
8456 999 continue
8457  !--- make sure the number of entry for mask_list is nmask
8458  if( n .NE. nmask) call mpp_error(fatal, &
8459  "fms_io(parse_mask_table_2d): number of mask_list entry does not match nmask in file "//trim(mask_table))
8460  call mpp_close(unit)
8461  endif
8462 
8463  call mpp_broadcast(mask_list, 2*nmask, mpp_root_pe())
8464  do n = 1, nmask
8465  if(debug_mask_list) then
8466  write(stdoutunit,*) "==>NOTE from parse_mask_table_2d: ", trim(modelname), " mask_list = ", mask_list(n,1), mask_list(n,2)
8467  endif
8468  maskmap(mask_list(n,1),mask_list(n,2)) = .false.
8469  enddo
8470 
8471  deallocate(mask_list)
8472 
8473 end subroutine parse_mask_table_2d
8474 
8475 
8476 !#######################################################################
8477 subroutine parse_mask_table_3d(mask_table, maskmap, modelname)
8479  character(len=*), intent(in) :: mask_table
8480  logical, intent(out) :: maskmap(:,:,:)
8481  character(len=*), intent(in) :: modelname
8482  integer :: nmask, layout(2)
8483  integer, allocatable :: mask_list(:,:)
8484  integer :: unit, mystat, n, stdoutunit, ntiles
8485  character(len=128) :: record
8486 
8487  maskmap = .true.
8488  nmask = 0
8489  stdoutunit = stdout()
8490  if( mpp_pe() == mpp_root_pe() ) then
8491  call mpp_open(unit, mask_table, action=mpp_rdonly)
8492  read(unit, fmt=*, iostat=mystat) nmask
8493  if( mystat /= 0 ) call mpp_error(fatal, &
8494  "fms_io(parse_mask_table_3d): Error reading nmask from file " //trim(mask_table))
8495  write(stdoutunit,*)"parse_mask_table: Number of domain regions masked in ", trim(modelname), " = ", nmask
8496  if( nmask > 0 ) then
8497  !--- read layout from mask_table and confirm it matches the shape of maskmap
8498  read(unit, fmt=*, iostat=mystat) layout(1), layout(2), ntiles
8499  if( mystat /= 0 ) call mpp_error(fatal, &
8500  "fms_io(parse_mask_talbe_3d): Error reading layout from file " //trim(mask_table))
8501  if( (layout(1) .NE. size(maskmap,1)) .OR. (layout(2) .NE. size(maskmap,2)) )then
8502  write(stdoutunit,*)"layout=", layout, ", size(maskmap) = ", size(maskmap,1), size(maskmap,2)
8503  call mpp_error(fatal, "fms_io(parse_mask_table_3d): layout in file "//trim(mask_table)// &
8504  "does not match size of maskmap for "//trim(modelname))
8505  endif
8506  if( ntiles .NE. size(maskmap,3) ) then
8507  write(stdoutunit,*)"ntiles=", ntiles, ", size(maskmap,3) = ", size(maskmap,3)
8508  call mpp_error(fatal, "fms_io(parse_mask_table_3d): ntiles in file "//trim(mask_table)// &
8509  "does not match size of maskmap for "//trim(modelname))
8510  endif
8511  !--- make sure mpp_npes() == layout(1)*layout(2) - nmask
8512  if( mpp_npes() .NE. layout(1)*layout(2)*ntiles - nmask ) then
8513  print*, "layout=", layout, nmask, mpp_npes()
8514  call mpp_error(fatal, &
8515  .NE."fms_io(parse_mask_table_3d): mpp_npes() layout(1)*layout(2) - nmask for "//trim(modelname))
8516  endif
8517  endif
8518  endif
8519 
8520  call mpp_broadcast(nmask, mpp_root_pe())
8521 
8522  if(nmask==0) then
8523  if( mpp_pe() == mpp_root_pe() ) call mpp_close(unit)
8524  return
8525  endif
8526 
8527  allocate(mask_list(nmask,3))
8528 
8529  if( mpp_pe() == mpp_root_pe() ) then
8530  n = 0
8531  do while( .true. )
8532  read(unit,'(a)',end=999) record
8533  if (record(1:1) == '#') cycle
8534  if (record(1:10) == ' ') cycle
8535  n = n + 1
8536  if( n > nmask ) then
8537  call mpp_error(fatal, "fms_io(parse_mask_table_3d): number of mask_list entry "// &
8538  "is greater than nmask in file "//trim(mask_table) )
8539  endif
8540  read(record,*,err=888) mask_list(n,1), mask_list(n,2), mask_list(n,3)
8541  enddo
8542 888 call mpp_error(fatal, "fms_io(parse_mask_table_3d): Error in reading mask_list from file "//trim(mask_table))
8543 
8544 999 continue
8545  !--- make sure the number of entry for mask_list is nmask
8546  if( n .NE. nmask) call mpp_error(fatal, &
8547  "fms_io(parse_mask_table_3d): number of mask_list entry does not match nmask in file "//trim(mask_table))
8548  call mpp_close(unit)
8549  endif
8550 
8551  call mpp_broadcast(mask_list, 3*nmask, mpp_root_pe())
8552  do n = 1, nmask
8553  if(debug_mask_list) then
8554  write(stdoutunit,*) "==>NOTE from parse_mask_table_3d: ", trim(modelname), " mask_list = ", &
8555  mask_list(n,1), mask_list(n,2), mask_list(n,3)
8556  endif
8557  maskmap(mask_list(n,1),mask_list(n,2),mask_list(n,3)) = .false.
8558  enddo
8559 
8560  deallocate(mask_list)
8561 
8562 end subroutine parse_mask_table_3d
8563 
8564 
8565 function get_great_circle_algorithm()
8567 
8568  if(.NOT. module_is_initialized) call mpp_error(fatal, &
8569  "fms_io(use_great_circle_algorithm): fms_io_init is not called yet")
8570 
8572 
8573 end function get_great_circle_algorithm
8574 
8575 !#######################################################################
8576 ! <SUBROUTINE NAME="write_version_number">
8577 
8578 ! <OVERVIEW>
8579 ! Prints to the log file (or a specified unit) the (cvs) version id string and
8580 ! (cvs) tag name.
8581 ! </OVERVIEW>
8582 ! <DESCRIPTION>
8583 ! Prints to the log file (stdlog) or a specified unit the (cvs) version id string
8584 ! and (cvs) tag name.
8585 ! </DESCRIPTION>
8586 ! <TEMPLATE>
8587 ! call write_version_number ( version [, tag, unit] )
8588 ! </TEMPLATE>
8589 
8590 ! <IN NAME="version" TYPE="character(len=*)">
8591 ! string that contains routine name and version number.
8592 ! </IN>
8593 ! <IN NAME="tag" TYPE="character(len=*)">
8594 ! The tag/name string, this is usually the Name string
8595 ! returned by CVS when checking out the code.
8596 ! </IN>
8597 ! <IN NAME="unit" TYPE="integer">
8598 ! The Fortran unit number of an open formatted file. If this unit number
8599 ! is not supplied the log file unit number is used (stdlog).
8600 ! </IN>
8601 ! prints module version number to the log file of specified unit number
8602 
8603 subroutine write_version_number (version, tag, unit)
8605 ! in: version = string that contains routine name and version number
8606 !
8607 ! optional in:
8608 ! tag = cvs tag name that code was checked out with
8609 ! unit = alternate unit number to direct output
8610 ! (default: unit=stdlog)
8611 
8612  character(len=*), intent(in) :: version
8613  character(len=*), intent(in), optional :: tag
8614  integer, intent(in), optional :: unit
8615 
8616  integer :: logunit
8617 
8618  if (.not.module_is_initialized) call fms_io_init ( )
8619 
8620  logunit = stdlog()
8621  if (present(unit)) then
8622  logunit = unit
8623  else
8624  ! only allow stdlog messages on root pe
8625  if ( mpp_pe() /= mpp_root_pe() ) return
8626  endif
8627 
8628  if (present(tag)) then
8629  write (logunit,'(/,80("="),/(a))') trim(version), trim(tag)
8630  else
8631  write (logunit,'(/,80("="),/(a))') trim(version)
8632  endif
8633 
8634 end subroutine write_version_number
8635 ! </SUBROUTINE>
8636 
8637 !----------
8638 !ug support
8639 #include <fms_io_unstructured_register_restart_axis.inc>
8640 #include <fms_io_unstructured_setup_one_field.inc>
8641 #include <fms_io_unstructured_register_restart_field.inc>
8642 #include <fms_io_unstructured_save_restart.inc>
8643 #include <fms_io_unstructured_read.inc>
8644 #include <fms_io_unstructured_get_file_name.inc>
8645 #include <fms_io_unstructured_get_file_unit.inc>
8646 #include <fms_io_unstructured_file_unit.inc>
8647 #include <fms_io_unstructured_get_field_size.inc>
8648 #include <fms_io_unstructured_field_exist.inc>
8649 !----------
8650 
8651 end module fms_io_mod
subroutine, public set_meta_global(fileObj, name, rval, ival, cval)
Definition: fms_io.F90:1498
integer function register_restart_field_r1d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, compressed_axis, read_only, restart_owns_data)
Definition: fms_io.F90:1601
logical function, public get_great_circle_algorithm()
Definition: fms_io.F90:8566
subroutine read_distributed_r3d(unit, fmt, iostat, data)
Definition: fms_io.F90:5620
subroutine, public set_domain(Domain2)
Definition: fms_io.F90:7401
integer function register_restart_field_r4d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only, restart_owns_data)
Definition: fms_io.F90:1794
logical fms_netcdf_restart
Definition: fms_io.F90:533
subroutine read_data_3d(unit, data, end)
Definition: fms_io.F90:6205
integer, parameter, private max_time_level_write
Definition: fms_io.F90:153
subroutine, public free_restart_type(fileObj)
Definition: fms_io.F90:1413
subroutine, public nullify_filename_appendix()
Definition: fms_io.F90:8359
integer max_files_w
Definition: fms_io.F90:538
subroutine read_data_iscalar_new(filename, fieldname, data, domain, timelevel, no_domain, tile_count)
Definition: fms_io.F90:5311
character(len=128), dimension(:), allocatable registered_file
Definition: fms_io.F90:497
subroutine save_unlimited_axis_restart(fileObj, restartpath)
Definition: fms_io.F90:2872
integer function register_restart_region_r2d(fileObj, filename, fieldname, data, indices, global_size, pelist, is_root_pe, longname, units, position, x_halo, y_halo, ishift, jshift, read_only, mandatory)
Definition: fms_io.F90:2359
type(atttype), save, public default_att
Definition: mpp_io.F90:1073
integer, private je
Definition: fms_io.F90:494
logical function query_initialized_id(fileObj, id)
Definition: fms_io.F90:6791
integer function, public open_direct_file(file, action, recl)
Definition: fms_io.F90:7280
subroutine register_restart_axis_i1d(fileObj, filename, fieldname, data, compressed, compressed_axis, dimlen, dimlen_name, dimlen_lname, units, longname, imin)
Definition: fms_io.F90:1296
integer function register_restart_field_r0d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only, restart_owns_data)
Definition: fms_io.F90:1568
logical function query_initialized_r2d(fileObj, f_ptr, name)
Definition: fms_io.F90:6853
subroutine write_data_1d_new(filename, fieldname, data, domain, no_domain, tile_count, data_default)
Definition: fms_io.F90:4819
integer function, private lookup_axis(axis_sizes, siz, domains, dom)
Definition: fms_io.F90:4891
integer, private jsd
Definition: fms_io.F90:495
integer, parameter, private max_domains
Definition: fms_io.F90:151
integer function register_restart_field_r1d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2021
character(len=128) error_msg
Definition: fms_io.F90:487
subroutine read_distributed_r1d(unit, fmt, iostat, data)
Definition: fms_io.F90:5650
subroutine read_compressed_i1d(filename, fieldname, data, domain, timelevel, start, nread, threading)
Definition: fms_io.F90:5448
logical time_stamp_restart
Definition: fms_io.F90:542
logical read_all_pe
Definition: fms_io.F90:536
subroutine reset_field_pointer_r4d(fileObj, id_field, data)
Definition: fms_io.F90:6504
integer function register_restart_field_r2d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2055
logical function, public file_exist(file_name, domain, no_domain)
Definition: fms_io.F90:8246
subroutine reset_field_pointer_i1d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6720
subroutine set_initialized_r2d(fileObj, f_ptr, name, is_set)
Definition: fms_io.F90:7038
integer function register_restart_field_r2d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, compressed, position, tile_count, data_default, longname, units, compressed_axis, read_only, restart_owns_data)
Definition: fms_io.F90:1635
integer, parameter max_axis_size
Definition: fms_io.F90:154
integer max_files_r
Definition: fms_io.F90:539
logical function do_read()
Definition: fms_io.F90:6395
subroutine reset_field_pointer_r2d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6654
character(len=32), save filename_appendix
Definition: fms_io.F90:523
subroutine write_data_4d(unit, data)
Definition: fms_io.F90:6337
subroutine read_compressed_i2d(filename, fieldname, data, domain, timelevel, start, nread, threading)
Definition: fms_io.F90:5462
integer function register_restart_region_r3d(fileObj, filename, fieldname, data, indices, global_size, pelist, is_root_pe, longname, units, position, x_halo, y_halo, ishift, jshift, read_only, mandatory)
Definition: fms_io.F90:2414
subroutine save_default_restart(fileObj, restartpath)
Definition: fms_io.F90:2958
logical read_data_bug
Definition: fms_io.F90:541
subroutine write_data_4d_new(filename, fieldname, data, domain, no_domain, position, tile_count, data_default)
Definition: fms_io.F90:4774
integer function, private unique_axes(file, index, id_axes, siz_axes, dom)
Definition: fms_io.F90:6066
subroutine parse_mask_table_3d(mask_table, maskmap, modelname)
Definition: fms_io.F90:8478
logical function get_global_att_value_text(file, att, attvalue)
Definition: fms_io.F90:7886
subroutine write_chksum(fileObj, action)
Definition: fms_io.F90:3804
subroutine read_compressed_1d(filename, fieldname, data, domain, timelevel, start, nread, threading)
Definition: fms_io.F90:5476
subroutine read_data_2d(unit, data, end)
Definition: fms_io.F90:6148
integer function register_restart_field_i1d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2234
subroutine write_data_3d(unit, data)
Definition: fms_io.F90:6314
subroutine write_ldata_2d(unit, data)
Definition: fms_io.F90:6280
subroutine, public reset_field_name(fileObj, id_field, name)
Definition: fms_io.F90:6402
subroutine, public write_version_number(version, tag, unit)
Definition: fms_io.F90:8604
subroutine parse_mask_table_2d(mask_table, maskmap, modelname)
Definition: fms_io.F90:8398
integer, parameter, private max_split_file
Definition: fms_io.F90:147
subroutine get_var_att_value_text(file, varname, attname, attvalue)
Definition: fms_io.F90:7869
subroutine, public get_field_size(filename, fieldname, siz, field_found, domain, no_domain)
Definition: fms_io.F90:5112
integer num_files_r
Definition: fms_io.F90:479
subroutine restore_state_all(fileObj, directory, nonfatal_missing_files)
Definition: fms_io.F90:3890
subroutine reset_field_pointer_i3d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6764
integer, private ieg
Definition: fms_io.F90:496
type(restart_file_type), dimension(:), allocatable files_read
Definition: fms_io.F90:498
integer function register_restart_field_r3d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only, compressed, compressed_axis, restart_owns_data)
Definition: fms_io.F90:1673
subroutine set_initialized_r3d(fileObj, f_ptr, name, is_set)
Definition: fms_io.F90:7085
type(domain1d), dimension(max_domains), save domain_y
Definition: fms_io.F90:501
integer function register_restart_field_i1d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, compressed_axis, read_only, restart_owns_data)
Definition: fms_io.F90:1868
subroutine read_compressed_3d(filename, fieldname, data, domain, timelevel)
Definition: fms_io.F90:5536
subroutine read_data_2d_region(filename, fieldname, data, start, nread, domain, no_domain, tile_count)
Definition: fms_io.F90:5662
integer, parameter, private max_axes
Definition: fms_io.F90:149
Definition: mpp.F90:39
subroutine read_distributed_i1d(unit, fmt, iostat, data)
Definition: fms_io.F90:5590
logical function query_initialized_r4d(fileObj, f_ptr, name)
Definition: fms_io.F90:6938
integer(int_kind), parameter, public ccidx
Definition: fms_io.F90:170
subroutine write_idata_2d(unit, data)
Definition: fms_io.F90:6290
subroutine read_distributed_iscalar(unit, fmt, iostat, data)
Definition: fms_io.F90:5605
subroutine read_data_i1d_new(filename, fieldname, data, domain, timelevel, no_domain, tile_count)
Definition: fms_io.F90:5295
subroutine read_ldata_2d(unit, data, end)
Definition: fms_io.F90:6162
subroutine set_initialized_r4d(fileObj, f_ptr, name, is_set)
Definition: fms_io.F90:7133
logical checksum_required
Definition: fms_io.F90:546
subroutine reset_field_pointer_i0d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6698
logical function all_field_read_only(fileObj)
Definition: fms_io.F90:2519
integer(int_kind), parameter, public uidx
Definition: fms_io.F90:169
integer, private jed
Definition: fms_io.F90:495
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
subroutine read_data_i3d_new(filename, fieldname, data, domain, timelevel, no_domain, position, tile_count)
Definition: fms_io.F90:5263
integer pack_size
Definition: fms_io.F90:552
subroutine read_compressed_2d(filename, fieldname, data, domain, timelevel, start, nread, threading)
Definition: fms_io.F90:5491
integer function, public dimension_size(filename, dimname, domain, no_domain)
Definition: fms_io.F90:5044
subroutine reset_field_pointer_r1d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6632
integer function register_restart_field_i3d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2316
subroutine, public set_filename_appendix(string_in)
Definition: fms_io.F90:8366
subroutine reset_field_pointer_i1d(fileObj, id_field, data)
Definition: fms_io.F90:6547
integer num_files_w
Definition: fms_io.F90:480
logical function, public get_file_name(orig_file, actual_file, read_dist, io_domain_exist, no_domain, domain, tile_count)
Definition: fms_io.F90:7944
logical print_chksum
Definition: fms_io.F90:543
subroutine register_restart_axis_unlimited(fileObj, filename, fieldname, nelem, units, longname)
Definition: fms_io.F90:1366
subroutine reset_field_pointer_r0d(fileObj, id_field, data)
Definition: fms_io.F90:6420
integer function, public open_ieee32_file(file, action)
Definition: fms_io.F90:7321
subroutine reset_field_pointer_r2d(fileObj, id_field, data)
Definition: fms_io.F90:6462
type(domain1d), dimension(max_domains), save domain_x
Definition: fms_io.F90:501
subroutine restore_state_one_field(fileObj, id_field, directory, nonfatal_missing_files)
Definition: fms_io.F90:4225
subroutine, public get_restart_io_mode(do_netcdf_restart)
Definition: fms_io.F90:623
subroutine read_data_i2d_new(filename, fieldname, data, domain, timelevel, no_domain, position, tile_count)
Definition: fms_io.F90:5279
type(domain2d), save, public null_domain2d
subroutine reset_field_pointer_r0d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6610
integer, parameter, public comm_tag_2
integer, private ied
Definition: fms_io.F90:495
subroutine reset_field_pointer_r3d(fileObj, id_field, data)
Definition: fms_io.F90:6483
subroutine read_distributed_r5d(unit, fmt, iostat, data)
Definition: fms_io.F90:5635
integer, private ie
Definition: fms_io.F90:494
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call mpp_error(FATAL, 'MPP_TRANSMIT:you cannot transmit to ANY_PE using MPI.') else if(to_pe.NE.NULL_PE) then !no other valid cases except NULL_PE call mpp_error(FATAL
subroutine, public get_domain_decomp(x, y)
Definition: fms_io.F90:7471
subroutine, public fms_io_init()
Definition: fms_io.F90:638
subroutine, public field_size(filename, fieldname, siz, field_found, domain, no_domain)
Definition: fms_io.F90:4941
subroutine write_data_2d(unit, data)
Definition: fms_io.F90:6270
integer num_domains
Definition: fms_io.F90:481
subroutine read_data_4d(unit, data, end)
Definition: fms_io.F90:6235
subroutine get_field_id(unit, index_file, fieldname, index_field, is_no_domain, is_not_dim)
Definition: fms_io.F90:8125
character(len=32) threading_read
Definition: fms_io.F90:534
type(axistype), save, public default_axis
Definition: mpp_io.F90:1071
subroutine get_file_unit(filename, unit, index_file, read_dist, io_domain_exist, domain)
Definition: fms_io.F90:8072
subroutine, public nullify_domain()
Definition: fms_io.F90:7421
logical debug_mask_list
Definition: fms_io.F90:545
integer, private isg
Definition: fms_io.F90:496
subroutine write_meta_global(unit, fileObj)
Definition: fms_io.F90:1539
subroutine write_data_3d_new(filename, fieldname, data, domain, no_domain, scalar_or_1d, position, tile_count, data_default)
Definition: fms_io.F90:1009
integer, parameter, private nidx
Definition: fms_io.F90:173
subroutine, public save_restart_border(fileObj, time_stamp, directory)
Definition: fms_io.F90:3354
subroutine reset_field_pointer_i3d(fileObj, id_field, data)
Definition: fms_io.F90:6589
subroutine, public restore_state_border(fileObj, directory, nonfatal_missing_files)
Definition: fms_io.F90:3644
integer function, public open_namelist_file(file)
Definition: fms_io.F90:7204
type(domain2d), pointer, private current_domain
Definition: fms_io.F90:492
integer thread_r
Definition: fms_io.F90:484
integer function register_restart_field_i2d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, compressed, position, tile_count, data_default, longname, units, compressed_axis, read_only, restart_owns_data)
Definition: fms_io.F90:1908
subroutine save_compressed_restart(fileObj, restartpath, append, time_level)
Definition: fms_io.F90:2543
subroutine read_data_1d_new(filename, fieldname, data, domain, timelevel, no_domain, tile_count)
Definition: fms_io.F90:6022
subroutine set_initialized_name(fileObj, name, is_set)
Definition: fms_io.F90:7004
subroutine reset_field_pointer_r3d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6676
integer, private jeg
Definition: fms_io.F90:496
integer num_registered_files
Definition: fms_io.F90:482
subroutine reset_field_pointer_i2d_2level(fileObj, id_field, data1, data2)
Definition: fms_io.F90:6742
integer, private js
Definition: fms_io.F90:494
subroutine reset_field_pointer_i0d(fileObj, id_field, data)
Definition: fms_io.F90:6526
logical function get_global_att_value_real(file, att, attvalue)
Definition: fms_io.F90:7914
subroutine reset_field_pointer_r1d(fileObj, id_field, data)
Definition: fms_io.F90:6441
subroutine, public get_mosaic_tile_file_ug(file_in, file_out, domain)
Definition: fms_io.F90:7813
integer(int_kind), parameter, public cidx
Definition: fms_io.F90:165
integer, parameter, private max_time_level_register
Definition: fms_io.F90:152
subroutine register_restart_axis_r1d(fileObj, filename, fieldname, data, cartesian, units, longname, sense, min, calendar)
Definition: fms_io.F90:1235
integer, parameter r8_kind
Definition: platform.F90:24
character(len=16) function string_from_integer(n)
Definition: fms_io.F90:7692
subroutine read_eof(end_found)
Definition: fms_io.F90:6381
logical great_circle_algorithm
Definition: fms_io.F90:488
integer function register_restart_field_i0d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only, restart_owns_data)
Definition: fms_io.F90:1828
subroutine read_data_scalar_new(filename, fieldname, data, domain, timelevel, no_domain, tile_count)
Definition: fms_io.F90:6042
subroutine read_distributed_a1d(unit, fmt, iostat, data)
Definition: fms_io.F90:5579
subroutine get_size(unit, fieldname, siz, found)
Definition: fms_io.F90:5175
integer function lookup_domain(domain)
Definition: fms_io.F90:4877
integer form
Definition: fms_io.F90:484
logical show_open_namelist_file_warning
Definition: fms_io.F90:544
integer, private is
Definition: fms_io.F90:494
subroutine, public fms_io_exit()
Definition: fms_io.F90:750
logical function query_initialized_r3d(fileObj, f_ptr, name)
Definition: fms_io.F90:6895
integer function, public open_restart_file(file, action)
Definition: fms_io.F90:7248
type(domain2d), dimension(max_domains), target, save array_domain
Definition: fms_io.F90:500
integer function, public open_file(file, form, action, access, threading, recl, dist)
Definition: fms_io.F90:7552
subroutine read_data_2d_ug(filename, fieldname, data, SG_domain, UG_domain, timelevel)
Definition: fms_io.F90:5959
character(len=32) function string_from_real(a)
Definition: fms_io.F90:7723
subroutine, public get_filename_appendix(string_out)
Definition: fms_io.F90:8350
integer, private jsg
Definition: fms_io.F90:496
#define max(a, b)
Definition: mosaic_util.h:33
subroutine, public get_tile_string(str_out, str_in, tile, str2_in)
Definition: fms_io.F90:7735
subroutine, public get_mosaic_tile_grid(grid_file, mosaic_file, domain, tile_count)
Definition: fms_io.F90:7850
integer(int_kind), parameter, public yidx
Definition: fms_io.F90:164
integer(int_kind), parameter, public hidx
Definition: fms_io.F90:167
subroutine write_data_i3d_new(filename, fieldname, data, domain, no_domain, position, tile_count, data_default)
Definition: fms_io.F90:944
subroutine get_axis_cart(axis, cart)
Definition: fms_io.F90:7483
subroutine read_data_3d_new(filename, fieldname, data, domain, timelevel, no_domain, scalar_or_1d, position, tile_count)
Definition: fms_io.F90:5326
subroutine write_data_scalar_new(filename, fieldname, data, domain, no_domain, tile_count, data_default)
Definition: fms_io.F90:4837
integer, parameter, private max_fields
Definition: fms_io.F90:148
subroutine write_data_2d_new(filename, fieldname, data, domain, no_domain, position, tile_count, data_default)
Definition: fms_io.F90:4799
subroutine, public get_instance_filename(name_in, name_out)
Definition: fms_io.F90:8379
subroutine read_data_2d_new(filename, fieldname, data, domain, timelevel, no_domain, position, tile_count)
Definition: fms_io.F90:5977
subroutine reset_field_pointer_i2d(fileObj, id_field, data)
Definition: fms_io.F90:6568
subroutine read_data_3d_region(filename, fieldname, data, start, nread, domain, no_domain, tile_count)
Definition: fms_io.F90:5710
integer, parameter, private max_atts
Definition: fms_io.F90:150
subroutine get_mosaic_tile_file_sg(file_in, file_out, is_no_domain, domain, tile_count)
Definition: fms_io.F90:7755
integer(int_kind), parameter, public zidx
Definition: fms_io.F90:166
logical fms_netcdf_override
Definition: fms_io.F90:532
type(restart_file_type), dimension(:), allocatable, target files_write
Definition: fms_io.F90:499
#define min(a, b)
Definition: mosaic_util.h:32
integer, private isd
Definition: fms_io.F90:495
subroutine read_idata_2d(unit, data, end)
Definition: fms_io.F90:6175
integer function register_restart_field_r3d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2089
integer(int_kind), parameter, public tidx
Definition: fms_io.F90:168
subroutine read_data_4d_new(filename, fieldname, data, domain, timelevel, no_domain, position, tile_count)
Definition: fms_io.F90:5899
subroutine set_initialized_id(fileObj, id, is_set)
Definition: fms_io.F90:6976
integer function register_restart_field_i0d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2193
character(len=64) iospec_ieee32
Definition: fms_io.F90:537
subroutine setup_one_field(fileObj, filename, fieldname, field_siz, index_field, domain, mandatory, no_domain, scalar_or_1d, position, tile_count, data_default, longname, units, compressed_axis, read_only, owns_data)
Definition: fms_io.F90:4538
integer dr_set_size
Definition: fms_io.F90:540
integer function, private lookup_field_r(nfile, fieldname)
Definition: fms_io.F90:4856
subroutine write_data_i1d_new(filename, fieldname, data, domain, no_domain, tile_count, data_default)
Definition: fms_io.F90:978
logical module_is_initialized
Definition: fms_io.F90:485
subroutine write_data_i2d_new(filename, fieldname, data, domain, no_domain, position, tile_count, data_default)
Definition: fms_io.F90:961
character(len=32) format
Definition: fms_io.F90:535
type(fieldtype), save, public default_field
Definition: mpp_io.F90:1072
logical function query_initialized_name(fileObj, name)
Definition: fms_io.F90:6816
subroutine, public close_file(unit, status, dist)
Definition: fms_io.F90:7363
subroutine file_unit(filename, found_file, unit, domain, no_domain)
Definition: fms_io.F90:4992
subroutine write_data_iscalar_new(filename, fieldname, data, domain, no_domain, tile_count, data_default)
Definition: fms_io.F90:993
integer function register_restart_field_i2d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:2275
subroutine, public return_domain(domain2)
Definition: fms_io.F90:7444
logical function, public field_exist(file_name, field_name, domain, no_domain)
Definition: fms_io.F90:8298
integer(int_kind), parameter, public xidx
Definition: fms_io.F90:163
subroutine, public save_restart(fileObj, time_stamp, directory, append, time_level)
Definition: fms_io.F90:2467
integer function register_restart_field_i3d(fileObj, filename, fieldname, data, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only, restart_owns_data)
Definition: fms_io.F90:1951
integer function register_restart_field_r0d_2level(fileObj, filename, fieldname, data1, data2, domain, mandatory, no_domain, position, tile_count, data_default, longname, units, read_only)
Definition: fms_io.F90:1989
subroutine read_data_text(filename, fieldname, data, level)
Definition: fms_io.F90:5859
type(domain1d), save, public null_domain1d