FMS  2024.03
Flexible Modeling System
mpp_io_misc.inc
1 ! -*-f90-*-
2 
3 !***********************************************************************
4 !* GNU Lesser General Public License
5 !*
6 !* This file is part of the GFDL Flexible Modeling System (FMS).
7 !*
8 !* FMS is free software: you can redistribute it and/or modify it under
9 !* the terms of the GNU Lesser General Public License as published by
10 !* the Free Software Foundation, either version 3 of the License, or (at
11 !* your option) any later version.
12 !*
13 !* FMS is distributed in the hope that it will be useful, but WITHOUT
14 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 !* for more details.
17 !*
18 !* You should have received a copy of the GNU Lesser General Public
19 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
20 !***********************************************************************
21 !> @file
22 !> @brief Misc. routines including initialization and finalization of @ref mpp_io_mod
23 
24 !> @addtogroup mpp_io_mod
25 !> @{
26 
27 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28 ! !
29 ! mpp_io_init: initialize parallel I/O !
30 ! !
31 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
32 
33 ! <SUBROUTINE NAME="mpp_io_init">
34 ! <OVERVIEW>
35 ! Initialize <TT>mpp_io_mod</TT>.
36 ! </OVERVIEW>
37 ! <DESCRIPTION>
38 ! Called to initialize the <TT>mpp_io_mod</TT> package. Sets the range
39 ! of valid fortran units and initializes the <TT>mpp_file</TT> array of
40 ! <TT>type(filetype)</TT>. <TT>mpp_io_init</TT> will call <TT>mpp_init</TT> and
41 ! <TT>mpp_domains_init</TT>, to make sure its parent modules have been
42 ! initialized. (Repeated calls to the <TT>init</TT> routines do no harm,
43 ! so don't worry if you already called it).
44 ! </DESCRIPTION>
45 ! <TEMPLATE>
46 ! call mpp_io_init( flags, maxunit )
47 ! </TEMPLATE>
48 ! <IN NAME="flags" TYPE="integer"></IN>
49 ! <IN NAME="maxunit" TYPE="integer"></IN>
50 ! </SUBROUTINE>
51 
52  subroutine mpp_io_init( flags, maxunit )
53  integer, intent(in), optional :: flags, maxunit
54  integer :: io_status, unit
55  integer :: logunit, outunit, inunit, errunit
56  logical :: opened
57  real(r8_kind) :: doubledata = 0
58  real :: realarray(4)
59 
60  if( module_is_initialized )return
61 
62 !initialize IO package: initialize mpp_file array, set valid range of units for fortran IO
63 
64  call mpp_init(flags) !if mpp_init has been called, this call will merely return
65  pe = mpp_pe()
66  npes = mpp_npes()
67  call mpp_domains_init(flags)
68 
69  maxunits = _max_file_units
70  if( PRESENT(maxunit) )maxunits = maxunit
71  if( PRESENT(flags) )then
72  debug = flags.EQ.mpp_debug
73  verbose = flags.EQ.mpp_verbose .OR. debug
74  end if
75 
76  !--- namelist
77  read (input_nml_file, mpp_io_nml, iostat=io_status)
78  if (io_status > 0) then
79  call mpp_error(fatal,'=>mpp_io_init: Error reading mpp_io_nml')
80  endif
81 
82 
83  outunit = stdout(); logunit=stdlog()
84  write(outunit, mpp_io_nml)
85  write(logunit, mpp_io_nml)
86 
87  unit_begin = 103
88  unit_end = maxunits
89 
90 !--- check the deflate level, set deflate = 1 if deflate_level is greater than equal to 0
91  if(deflate_level .GE. 0) deflate = 1
92  if(deflate .NE. 0) then
93  if(deflate_level <0 .OR. deflate > 9) then
94  call mpp_error(fatal, "mpp_io_mod(mpp_io_init): mpp_io_nml variable must be between 0 and 9 when set")
95  endif
96  endif
97 
98 ! determine the pack_size
99  pack_size = size(transfer(doubledata, realarray))
100  if( pack_size .NE. 1 .AND. pack_size .NE. 2) call mpp_error(fatal, &
101  & 'mpp_io_mod(mpp_io_init): pack_size should be 1 or 2')
102 
103 !initialize default_field
104  default_field%name = 'noname'
105  default_field%units = 'nounits'
106  default_field%longname = 'noname'
107  default_field%id = -1
108  default_field%type = -1
109  default_field%natt = -1
110  default_field%ndim = -1
111  default_field%checksum = 0
112 !largest possible 4-byte reals
113  default_field%min = -huge(1._4)
114  default_field%max = huge(1._4)
115  default_field%missing = mpp_fill_double ! now using netcdf:NF_FILL_DOUBLE instead of -1e36
116  default_field%fill = mpp_fill_double ! now using netcdf:NF_FILL_DOUBLE instead of -1e36
117  default_field%scale = 1.0
118  default_field%add = 0.0
119  default_field%pack = 1
120  default_field%time_axis_index = -1 !this value will never match any index
121 ! Initialize default axis
122  default_axis%name = 'noname'
123  default_axis%units = 'nounits'
124  default_axis%longname = 'noname'
125  default_axis%cartesian = 'none'
126  default_axis%compressed = 'unspecified'
127  default_axis%calendar = 'unspecified'
128  default_axis%sense = 0
129  default_axis%len = -1
130  default_axis%id = -1
131  default_axis%did = -1
132  default_axis%type = -1
133  default_axis%natt = -1
134 ! Initialize default attribute
135  default_att%name = 'noname'
136  default_att%type = -1
137  default_att%len = -1
138  default_att%catt = 'none'
139 
140 !up to MAXUNITS fortran units and MAXUNITS netCDF units are supported
141 !file attributes (opened, format, access, threading, fileset) are saved against the unit number
142 !external handles to netCDF units are saved from maxunits+1:2*maxunits
143  allocate( mpp_file(nullunit:2*maxunits) ) !starts at NULLUNIT=-1, used by non-participant PEs in
144  !! single-threaded I/O
145  mpp_file(:)%name = ' '
146  mpp_file(:)%action = -1
147  mpp_file(:)%format = -1
148  mpp_file(:)%threading = -1
149  mpp_file(:)%fileset = -1
150  mpp_file(:)%record = -1
151  mpp_file(:)%ncid = -1
152  mpp_file(:)%opened = .false.
153  mpp_file(:)%initialized = .false.
154  mpp_file(:)%write_on_this_pe = .false.
155  mpp_file(:)%io_domain_exist = .false.
156  mpp_file(:)%time_level = 0
157  mpp_file(:)%time = nulltime
158  mpp_file(:)%id = -1
159  mpp_file(:)%valid = .false.
160  mpp_file(:)%ndim = -1
161  mpp_file(:)%nvar = -1
162 !NULLUNIT "file" is always single-threaded, open and initialized (to pass checks in mpp_write)
163  mpp_file(nullunit)%threading = mpp_single
164  mpp_file(nullunit)%opened = .true.
165  mpp_file(nullunit)%valid = .true.
166  mpp_file(nullunit)%initialized = .true.
167 !! Declare the stdunits to be open
168 !! Because the stdunits are created with the newunit intrinsic function in some cases,
169 !! only open up an mpp_file array for units that are within the allocated scope of mpp_file
170  if (outunit > nullunit .AND. outunit < 2*maxunits) mpp_file(outunit)%opened = .true.
171  if (logunit > nullunit .AND. logunit < 2*maxunits) mpp_file(logunit)%opened = .true.
172  inunit = stdin()
173  if (inunit > nullunit .AND. inunit < 2*maxunits) mpp_file(inunit)%opened = .true.
174  errunit = stderr()
175  if (errunit > nullunit .AND. errunit < 2*maxunits) mpp_file(errunit)%opened = .true.
176 
177  if( pe.EQ.mpp_root_pe() )then
178  unit = stdlog() ! PGI compiler does not like stdlog() doing I/O within write call
179  write( unit,'(/a)' )'MPP_IO module '//trim(version)
180 #ifdef use_netCDF
181  text = nf_inq_libvers()
182  write( unit,'(/a)' )'Using netCDF library version '//trim(text)
183 #endif
184  endif
185 
186  call mpp_io_set_stack_size(131072) ! default initial value
187  call mpp_sync()
188  if( io_clocks_on )then
189  mpp_read_clock = mpp_clock_id( 'mpp_read')
190  mpp_write_clock = mpp_clock_id( 'mpp_write')
191  mpp_open_clock = mpp_clock_id( 'mpp_open')
192  mpp_close_clock = mpp_clock_id( 'mpp_close')
193  endif
194  module_is_initialized = .true.
195  return
196  end subroutine mpp_io_init
197 
198 
199 ! <SUBROUTINE NAME="mpp_io_exit">
200 ! <OVERVIEW>
201 ! Exit <TT>mpp_io_mod</TT>.
202 ! </OVERVIEW>
203 ! <DESCRIPTION>
204 ! It is recommended, though not at present required, that you call this
205 ! near the end of a run. This will close all open files that were opened
206 ! with <LINK SRC="#mpp_open"><TT>mpp_open</TT></LINK>. Files opened otherwise
207 ! are not affected.
208 ! </DESCRIPTION>
209 ! <TEMPLATE>
210 ! call mpp_io_exit()
211 ! </TEMPLATE>
212 ! </SUBROUTINE>
213 
214  subroutine mpp_io_exit(string)
215  character(len=*), optional :: string
216  integer :: unit,istat
217  logical :: dosync
218 
219  if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_IO_EXIT: must first call mpp_io_init.' )
220  dosync = .true.
221  if( PRESENT(string) )then
222  dosync = .NOT.( trim(string).EQ.'NOSYNC' )
223  end if
224 !close all open fortran units
225  do unit = unit_begin,unit_end
226  if( mpp_file(unit)%opened )FLUSH(unit)
227  end do
228  if( dosync )call mpp_sync()
229  do unit = unit_begin,unit_end
230  if( mpp_file(unit)%opened )close(unit)
231  end do
232 #ifdef use_netCDF
233 !close all open netCDF units
234  do unit = maxunits+1,2*maxunits
235  if( mpp_file(unit)%opened )error = nf_close(mpp_file(unit)%ncid)
236  end do
237 #endif
238 
239 ! call mpp_max(mpp_io_stack_hwm)
240 
241  if( pe.EQ.mpp_root_pe() )then
242 ! write( stdout,'(/a)' )'Exiting MPP_IO module...'
243 ! write( stdout,* )'MPP_IO_STACK high water mark=', mpp_io_stack_hwm
244  end if
245  deallocate(mpp_file)
246  module_is_initialized = .false.
247  return
248  end subroutine mpp_io_exit
249 
250 
251  subroutine netcdf_err( err, file, axis, field, attr, string )
252  integer, intent(in) :: err
253  type(filetype), optional :: file
254  type(axistype), optional :: axis
255  type(fieldtype), optional :: field
256  type(atttype), optional :: attr
257  character(len=*), optional :: string
258  character(len=256) :: errmsg
259 
260 #ifdef use_netCDF
261  if( err.EQ.nf_noerr )return
262  errmsg = nf_strerror(err)
263  if( PRESENT(file) )errmsg = trim(errmsg)//' File='//file%name
264  if( PRESENT(axis) )errmsg = trim(errmsg)//' Axis='//axis%name
265  if( PRESENT(field) )errmsg = trim(errmsg)//' Field='//field%name
266  if( PRESENT(attr) )errmsg = trim(errmsg)//' Attribute='//attr%name
267  if( PRESENT(string) )errmsg = trim(errmsg)//string
268  call mpp_io_exit('NOSYNC') !make sure you close all open files
269  call mpp_error( fatal, 'NETCDF ERROR: '//trim(errmsg) )
270 #endif
271  return
272  end subroutine netcdf_err
273 
274 
275  subroutine mpp_flush(unit)
276 !flush the output on a unit, syncing with disk
277  integer, intent(in) :: unit
278 
279  if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_FLUSH: must first call mpp_io_init.' )
280  if( .NOT.mpp_file(unit)%write_on_this_pe) return
281  if( .NOT.mpp_file(unit)%opened ) call mpp_error( fatal, 'MPP_FLUSH: invalid unit number.' )
282  if( .NOT.mpp_file(unit)%initialized )call mpp_error( fatal, &
283  & 'MPP_FLUSH: cannot flush a file during writing of metadata.' )
284 
285  if( mpp_file(unit)%format.EQ.mpp_netcdf )then
286 #ifdef use_netCDF
287  error = nf_sync(mpp_file(unit)%ncid); call netcdf_err( error, mpp_file(unit) )
288 #endif
289  else
290  FLUSH(unit)
291  end if
292  return
293  end subroutine mpp_flush
294 
295  !> Return the maximum number of MPP file units available.
296  !!
297  !! maxunits is a mpp_io_mod module variable and defines the maximum number
298  !! of Fortran file units that can be open simultaneously. mpp_get_maxunits
299  !! simply returns this number.
300  integer function mpp_get_maxunits()
301  mpp_get_maxunits = maxunits
302  end function mpp_get_maxunits
303 
304  logical function do_cf_compliance()
305  do_cf_compliance = cf_compliance
306  end function do_cf_compliance
307 !> @}
subroutine mpp_domains_init(flags)
Initialize domain decomp package.
subroutine mpp_io_set_stack_size(n)
Set the mpp_io_stack variable to be at least n LONG words long.
integer function mpp_get_maxunits()
Return the maximum number of MPP file units available.
integer function stdout()
This function returns the current standard fortran unit numbers for output.
Definition: mpp_util.inc:43
subroutine mpp_init(flags, localcomm, test_level, alt_input_nml_path)
Initialize the mpp_mod module. Must be called before any usage.
integer function stderr()
This function returns the current standard fortran unit numbers for error messages.
Definition: mpp_util.inc:51
integer function stdlog()
This function returns the current standard fortran unit numbers for log messages. Log messages,...
Definition: mpp_util.inc:59
integer function mpp_npes()
Returns processor count for current pelist.
Definition: mpp_util.inc:421
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:407
subroutine mpp_sync(pelist, do_self)
Synchronize PEs in list.
integer function mpp_clock_id(name, flags, grain)
Return an ID for a new or existing clock.
Definition: mpp_util.inc:705
integer function stdin()
This function returns the current standard fortran unit numbers for input.
Definition: mpp_util.inc:36