FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
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_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.
subroutine mpp_sync(pelist, do_self)
Synchronize PEs in list.