FV3 Bundle
mpp_io_write.inc
Go to the documentation of this file.
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 
22 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23 ! !
24 ! MPP_WRITE_META !
25 ! !
26 ! This series of routines is used to describe the contents of the file !
27 ! being written on <unit>. Each file can contain any number of fields, !
28 ! which can be functions of 0-3 spatial axes and 0-1 time axes. Axis !
29 ! descriptors are stored in the <axistype> structure and field !
30 ! descriptors in the <fieldtype> structure. !
31 ! !
32 ! type, public :: axistype !
33 ! sequence !
34 ! character(len=128) :: name !
35 ! character(len=128) :: units !
36 ! character(len=256) :: longname !
37 ! integer :: sense !+/-1, depth or height? !
38 ! type(domain1D) :: domain !
39 ! real, pointer :: data(:) !axis values (not used if time axis) !
40 ! integer :: id !
41 ! end type axistype !
42 ! !
43 ! type, public :: fieldtype !
44 ! sequence !
45 ! character(len=128) :: name !
46 ! character(len=128) :: units !
47 ! character(len=256) :: longname !
48 ! character(len=256) :: standard_name !CF standard name !
49 ! real :: min, max, missing, fill, scale, add !
50 ! type(axistype), pointer :: axis(:) !
51 ! integer :: id !
52 ! end type fieldtype !
53 ! !
54 ! The metadata contained in the type is always written for each axis and !
55 ! field. Any other metadata one wishes to attach to an axis or field !
56 ! can subsequently be passed to mpp_write_meta using the ID, as shown below. !
57 ! !
58 ! mpp_write_meta can take several forms: !
59 ! !
60 ! mpp_write_meta( unit, name, rval=rval, pack=pack ) !
61 ! mpp_write_meta( unit, name, ival=ival ) !
62 ! mpp_write_meta( unit, name, cval=cval ) !
63 ! integer, intent(in) :: unit !
64 ! character(len=*), intent(in) :: name !
65 ! real, intent(in), optional :: rval(:) !
66 ! integer, intent(in), optional :: ival(:) !
67 ! character(len=*), intent(in), optional :: cval !
68 ! !
69 ! This form defines global metadata associated with the file as a !
70 ! whole. The attribute is named <name> and can take on a real, integer !
71 ! or character value. <rval> and <ival> can be scalar or 1D arrays. !
72 ! !
73 ! mpp_write_meta( unit, id, name, rval=rval, pack=pack ) !
74 ! mpp_write_meta( unit, id, name, ival=ival ) !
75 ! mpp_write_meta( unit, id, name, cval=cval ) !
76 ! integer, intent(in) :: unit, id !
77 ! character(len=*), intent(in) :: name !
78 ! real, intent(in), optional :: rval(:) !
79 ! integer, intent(in), optional :: ival(:) !
80 ! character(len=*), intent(in), optional :: cval !
81 ! !
82 ! This form defines metadata associated with a previously defined !
83 ! axis or field, identified to mpp_write_meta by its unique ID <id>. !
84 ! The attribute is named <name> and can take on a real, integer !
85 ! or character value. <rval> and <ival> can be scalar or 1D arrays. !
86 ! This need not be called for attributes already contained in !
87 ! the type. !
88 ! !
89 ! PACK can take values 1,2,4,8. This only has meaning when writing !
90 ! floating point numbers. The value of PACK defines the number of words !
91 ! written into 8 bytes. For pack=4 and pack=8, an integer value is !
92 ! written: rval is assumed to have been scaled to the appropriate dynamic !
93 ! range. !
94 ! PACK currently only works for netCDF files, and is ignored otherwise. !
95 ! !
96 ! subroutine mpp_write_meta_axis( unit, axis, name, units, longname, & !
97 ! cartesian, sense, domain, data ) !
98 ! integer, intent(in) :: unit !
99 ! type(axistype), intent(inout) :: axis !
100 ! character(len=*), intent(in) :: name, units, longname !
101 ! character(len=*), intent(in), optional :: cartesian !
102 ! integer, intent(in), optional :: sense !
103 ! type(domain1D), intent(in), optional :: domain !
104 ! real, intent(in), optional :: data(:) !
105 ! !
106 ! This form defines a time or space axis. Metadata corresponding to the !
107 ! type above are written to the file on <unit>. A unique ID for subsequent !
108 ! references to this axis is returned in axis%id. If the <domain> !
109 ! element is present, this is recognized as a distributed data axis !
110 ! and domain decomposition information is also written if required (the !
111 ! domain decomposition info is required for multi-fileset multi-threaded !
112 ! I/O). If the <datLINK> element is allocated, it is considered to be a !
113 ! space axis, otherwise it is a time axis with an unlimited dimension. !
114 ! Only one time axis is allowed per file. !
115 ! !
116 ! subroutine mpp_write_meta_field( unit, field, axes, name, units, longname !
117 ! stanadard_name, min, max, missing, fill, scale, add, pack) !
118 ! integer, intent(in) :: unit !
119 ! type(fieldtype), intent(out) :: field !
120 ! type(axistype), intent(in) :: axes(:) !
121 ! character(len=*), intent(in) :: name, units, longname, standard_name !
122 ! real, intent(in), optional :: min, max, missing, fill, scale, add !
123 ! integer, intent(in), optional :: pack !
124 ! !
125 ! This form defines a field. Metadata corresponding to the type !
126 ! above are written to the file on <unit>. A unique ID for subsequent !
127 ! references to this field is returned in field%id. At least one axis !
128 ! must be associated, 0D variables are not considered. mpp_write_meta !
129 ! must previously have been called on all axes associated with this !
130 ! field. !
131 ! !
132 ! The mpp_write_meta package also includes subroutines write_attribute and !
133 ! write_attribute_netcdf, that are private to this module. !
134 ! !
135 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
136  subroutine mpp_write_meta_global( unit, name, rval, ival, cval, pack)
137 !writes a global metadata attribute to unit <unit>
138 !attribute <name> can be an real, integer or character
139 !one and only one of rval, ival, and cval should be present
140 !the first found will be used
141 !for a non-netCDF file, it is encoded into a string "GLOBAL <name> <val>"
142  integer, intent(in) :: unit
143  character(len=*), intent(in) :: name
144  real, intent(in), optional :: rval(:)
145  integer, intent(in), optional :: ival(:)
146  character(len=*), intent(in), optional :: cval
147  integer, intent(in), optional :: pack
148 
149 ! call mpp_clock_begin(mpp_write_clock)
150  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
151  if( .NOT. mpp_file(unit)%write_on_this_pe) then
152 ! call mpp_clock_end(mpp_write_clock)
153  return
154  endif
155  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
156  if( mpp_file(unit)%initialized ) &
157  call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
158 
159  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
160 #ifdef use_netCDF
161  call write_attribute_netcdf( unit, NF_GLOBAL, name, rval, ival, cval, pack )
162 #endif
163  else
164  call write_attribute( unit, 'GLOBAL '//trim(name), rval, ival, cval, pack )
165  end if
166 ! call mpp_clock_end(mpp_write_clock)
167 
168  return
169  end subroutine mpp_write_meta_global
170 
171 !versions of above to support <rval> and <ival> as scalars (because of f90 strict rank matching)
172  subroutine mpp_write_meta_global_scalar_r( unit, name, rval, pack )
173  integer, intent(in) :: unit
174  character(len=*), intent(in) :: name
175  real, intent(in) :: rval
176  integer, intent(in), optional :: pack
177 
178  call mpp_write_meta_global( unit, name, rval=(/rval/), pack=pack )
179  return
180  end subroutine mpp_write_meta_global_scalar_r
181 
182  subroutine mpp_write_meta_global_scalar_i( unit, name, ival, pack )
183  integer, intent(in) :: unit
184  character(len=*), intent(in) :: name
185  integer, intent(in) :: ival
186  integer, intent(in), optional :: pack
187 
188  call mpp_write_meta_global( unit, name, ival=(/ival/), pack=pack )
189  return
190  end subroutine mpp_write_meta_global_scalar_i
191 
192  subroutine mpp_write_meta_var( unit, id, name, rval, ival, cval, pack)
193 !writes a metadata attribute for variable <id> to unit <unit>
194 !attribute <name> can be an real, integer or character
195 !one and only one of rval, ival, and cval should be present
196 !the first found will be used
197 !for a non-netCDF file, it is encoded into a string "<id> <name> <val>"
198  integer, intent(in) :: unit, id
199  character(len=*), intent(in) :: name
200  real, intent(in), optional :: rval(:)
201  integer, intent(in), optional :: ival(:)
202  character(len=*), intent(in), optional :: cval
203  integer, intent(in), optional :: pack
204 
205  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
206  if( .NOT. mpp_file(unit)%write_on_this_pe) then
207  return
208  endif
209  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
210  if( mpp_file(unit)%initialized ) &
211  call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
212 
213  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
214  call write_attribute_netcdf( unit, id, name, rval, ival, cval, pack )
215  else
216  write( text, '(a,i4,a)' )'VARIABLE ', id, ' '//name
217  call write_attribute( unit, trim(text), rval, ival, cval, pack )
218  end if
219 
220  return
221  end subroutine mpp_write_meta_var
222 
223 !versions of above to support <rval> and <ival> as scalar (because of f90 strict rank matching)
224  subroutine mpp_write_meta_scalar_r( unit, id, name, rval, pack )
225  integer, intent(in) :: unit, id
226  character(len=*), intent(in) :: name
227  real, intent(in) :: rval
228  integer, intent(in), optional :: pack
229 
230  call mpp_write_meta( unit, id, name, rval=(/rval/), pack=pack )
231  return
232  end subroutine mpp_write_meta_scalar_r
233 
234  subroutine mpp_write_meta_scalar_i( unit, id, name, ival,pack )
235  integer, intent(in) :: unit, id
236  character(len=*), intent(in) :: name
237  integer, intent(in) :: ival
238  integer, intent(in), optional :: pack
239 
240  call mpp_write_meta( unit, id, name, ival=(/ival/),pack=pack )
241  return
242  end subroutine mpp_write_meta_scalar_i
243 
244 
245  subroutine mpp_write_axis_data (unit, axes )
246  integer, intent(in) :: unit
247  type(axistype), dimension(:), intent(in) :: axes
248 
249  integer :: naxis
250 
251  naxis = size (axes)
252  allocate (mpp_file(unit)%axis(naxis))
253  mpp_file(unit)%axis(1:naxis) = axes(1:naxis)
254 #ifdef use_netCDF
255  if( mpp_file(unit)%action.EQ.MPP_WRONLY )then
256  if(header_buffer_val>0) then
257  error = NF__ENDDEF(mpp_file(unit)%ncid,header_buffer_val,4,0,4)
258  else
259  error = NF_ENDDEF(mpp_file(unit)%ncid)
260  endif
261  endif
262 #endif
263  end subroutine mpp_write_axis_data
264 
265  subroutine mpp_def_dim_nodata(unit,name,size)
266  integer, intent(in) :: unit
267  character(len=*), intent(in) :: name
268  integer, intent(in) :: size
269  integer :: error,did
270 
271  ! This routine assumes the file is in define mode
272  if(.NOT. mpp_file(unit)%write_on_this_pe) return
273 #ifdef use_netCDF
274  error = NF_DEF_DIM(mpp_file(unit)%ncid,name,size,did)
275  call netcdf_err(error, mpp_file(unit),string='Axis='//trim(name))
276 #endif
277  end subroutine mpp_def_dim_nodata
278 
279  subroutine mpp_def_dim_int(unit,name,dsize,longname,data)
280  integer, intent(in) :: unit
281  character(len=*), intent(in) :: name
282  integer, intent(in) :: dsize
283  character(len=*), intent(in) :: longname
284  integer, intent(in) :: data(:)
285  integer :: error,did,id
286 
287  ! This routine assumes the file is in define mode
288 #ifdef use_netCDF
289  if(.NOT. mpp_file(unit)%write_on_this_pe) return
290  error = NF_DEF_DIM(mpp_file(unit)%ncid,name,dsize,did)
291  call netcdf_err(error, mpp_file(unit),string='Axis='//trim(name))
292 
293  ! Write dimension data.
294  error = NF_DEF_VAR( mpp_file(unit)%ncid, name, NF_INT, 1, did, id )
295  call netcdf_err( error, mpp_file(unit), string=' axis varable '//trim(name))
296 
297  error = NF_PUT_ATT_TEXT( mpp_file(unit)%ncid, id, 'long_name', len_trim(longname), longname )
298  call netcdf_err( error, mpp_file(unit), string=' Attribute=long_name' )
299 
300  if( mpp_file(unit)%action.EQ.MPP_WRONLY )then
301  if(header_buffer_val>0) then
302  error = NF__ENDDEF(mpp_file(unit)%ncid,header_buffer_val,4,0,4)
303  else
304  error = NF_ENDDEF(mpp_file(unit)%ncid)
305  endif
306  endif
307  call netcdf_err( error, mpp_file(unit), string=' subroutine mpp_def_dim')
308  error = NF_PUT_VARA_INT ( mpp_file(unit)%ncid, id, 1, size(data), data )
309  call netcdf_err( error, mpp_file(unit), string=' axis varable '//trim(name))
310  error = NF_REDEF(mpp_file(unit)%ncid)
311  call netcdf_err( error, mpp_file(unit), string=' subroutine mpp_def_dim')
312 #endif
313  return
314  end subroutine mpp_def_dim_int
315 
316  subroutine mpp_def_dim_real(unit,name,dsize,longname,data)
317  integer, intent(in) :: unit
318  character(len=*), intent(in) :: name
319  integer, intent(in) :: dsize
320  character(len=*), intent(in) :: longname
321  real, intent(in) :: data(:)
322  integer :: error,did,id
323 
324  ! This routine assumes the file is in define mode
325 #ifdef use_netCDF
326  if(.NOT. mpp_file(unit)%write_on_this_pe) return
327  error = NF_DEF_DIM(mpp_file(unit)%ncid,name,dsize,did)
328  call netcdf_err(error, mpp_file(unit),string='Axis='//trim(name))
329 
330  ! Write dimension data.
331  error = NF_DEF_VAR( mpp_file(unit)%ncid, name, NF_INT, 1, did, id )
332  call netcdf_err( error, mpp_file(unit), string=' axis varable '//trim(name))
333 
334  error = NF_PUT_ATT_TEXT( mpp_file(unit)%ncid, id, 'long_name', len_trim(longname), longname )
335  call netcdf_err( error, mpp_file(unit), string=' Attribute=long_name' )
336 
337  if( mpp_file(unit)%action.EQ.MPP_WRONLY )then
338  if(header_buffer_val>0) then
339  error = NF__ENDDEF(mpp_file(unit)%ncid,header_buffer_val,4,0,4)
340  else
341  error = NF_ENDDEF(mpp_file(unit)%ncid)
342  endif
343  endif
344  call netcdf_err( error, mpp_file(unit), string=' subroutine mpp_def_dim')
345  error = NF_PUT_VARA_INT ( mpp_file(unit)%ncid, id, 1, size(data), data )
346  call netcdf_err( error, mpp_file(unit), string=' axis varable '//trim(name))
347  error = NF_REDEF(mpp_file(unit)%ncid)
348  call netcdf_err( error, mpp_file(unit), string=' subroutine mpp_def_dim')
349 #endif
350  return
351  end subroutine mpp_def_dim_real
352 
353 
354 
355  subroutine mpp_write_meta_axis_r1d( unit, axis, name, units, longname, cartesian, sense, domain, data, min, calendar)
356 !load the values in an axistype (still need to call mpp_write)
357 !write metadata attributes for axis
358 !it is declared intent(inout) so you can nullify pointers in the incoming object if needed
359 !the f90 standard doesn't guarantee that intent(out) on a type guarantees that its pointer components will be unassociated
360  integer, intent(in) :: unit
361  type(axistype), intent(inout) :: axis
362  character(len=*), intent(in) :: name, units, longname
363  character(len=*), intent(in), optional :: cartesian
364  integer, intent(in), optional :: sense
365  type(domain1D), intent(in), optional :: domain
366  real, intent(in), optional :: data(:)
367  real, intent(in), optional :: min
368  character(len=*), intent(in), optional :: calendar
369 
370  integer :: is, ie, isg, ieg
371  integer :: istat
372  logical :: domain_exist
373  type(domain2d), pointer :: io_domain => NULL()
374 
375 ! call mpp_clock_begin(mpp_write_clock)
376  !--- the shift and cartesian information is needed in mpp_write_meta_field from all the pe.
377  !--- we may revise this in the future.
378  axis%cartesian = 'N'
379  if( PRESENT(cartesian) )axis%cartesian = cartesian
380 
381  domain_exist = .false.
382 
383  if( PRESENT(domain) ) then
384  domain_exist = .true.
385  call mpp_get_global_domain( domain, isg, ieg )
386  if(mpp_file(unit)%io_domain_exist) then
387  io_domain => mpp_get_io_domain(mpp_file(unit)%domain)
388  if(axis%cartesian=='X') then
389  call mpp_get_global_domain( io_domain, xbegin=is, xend=ie)
390  else if(axis%cartesian=='Y') then
391  call mpp_get_global_domain( io_domain, ybegin=is, yend=ie)
392  endif
393  else
394  call mpp_get_compute_domain( domain, is, ie )
395  endif
396  else if( PRESENT(data) )then
397  isg=1; ieg=size(data(:)); is=isg; ie=ieg
398  endif
399 
400  axis%shift = 0
401  if( PRESENT(data) .AND. domain_exist ) then
402  if( size(data(:)) == ieg-isg+2 ) then
403  axis%shift = 1
404  ie = ie + 1
405  ieg = ieg + 1
406  endif
407  endif
408 
409  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
410  if( .NOT. mpp_file(unit)%write_on_this_pe) then
411 ! call mpp_clock_end(mpp_write_clock)
412  return
413  endif
414  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
415  if( mpp_file(unit)%initialized ) &
416  call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
417 
418 !pre-existing pointers need to be nullified
419  if( ASSOCIATED(axis%data) ) then
420  DEALLOCATE(axis%data, stat=istat)
421  endif
422 !load axistype
423  axis%name = name
424  axis%units = units
425  axis%longname = longname
426  if( PRESENT(calendar) ) axis%calendar = calendar
427  if( PRESENT(sense) ) axis%sense = sense
428  if( PRESENT(data) )then
429  if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. domain_exist ) then
430  axis%len = ie - is + 1
431  allocate(axis%data(axis%len))
432  axis%data = data(is-isg+1:ie-isg+1)
433  else
434  axis%len = size(data(:))
435  allocate(axis%data(axis%len))
436  axis%data = data
437  endif
438  endif
439 !write metadata
440  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
441 #ifdef use_netCDF
442 !write axis def
443 !space axes are always floats, time axis is always double
444  if( ASSOCIATED(axis%data) )then !space axis
445  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, axis%len, axis%did )
446  call netcdf_err( error, mpp_file(unit), axis )
447  if(pack_size == 1) then
448  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id )
449  else ! pack_size == 2
450  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id )
451  endif
452  call netcdf_err( error, mpp_file(unit), axis )
453  else !time axis
454  if( mpp_file(unit)%id.NE.-1 ) &
455  call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
456  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, NF_UNLIMITED, axis%did )
457  call netcdf_err( error, mpp_file(unit), axis )
458  if(pack_size == 1) then
459  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id )
460  else ! pack_size == 2
461  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id )
462  endif
463  call netcdf_err( error, mpp_file(unit), axis )
464  mpp_file(unit)%id = axis%id !file ID is the same as time axis varID
465  end if
466 #endif
467  else
468  varnum = varnum + 1
469  axis%id = varnum
470  axis%did = varnum
471 !write axis def
472  write( text, '(a,i4,a)' )'AXIS ', axis%id, ' name'
473  call write_attribute( unit, trim(text), cval=axis%name )
474  write( text, '(a,i4,a)' )'AXIS ', axis%id, ' size'
475  if( ASSOCIATED(axis%data) )then !space axis
476 ! if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
477 ! call write_attribute( unit, trim(text), ival=(/ie-is+1/) )
478 ! else
479  call write_attribute( unit, trim(text), ival=(/size(axis%data(:))/) )
480 ! end if
481  else !time axis
482  if( mpp_file(unit)%id.NE.-1 ) &
483  call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
484  call write_attribute( unit, trim(text), ival=(/0/) ) !a size of 0 indicates time axis
485  mpp_file(unit)%id = axis%id
486  end if
487  end if
488 !write axis attributes
489  call mpp_write_meta( unit, axis%id, 'long_name', cval=axis%longname) ; axis%natt = axis%natt + 1
490  if (lowercase(trim(axis%units)).ne.'none' .OR. .NOT.cf_compliance) then
491  call mpp_write_meta( unit, axis%id, 'units', cval=axis%units) ; axis%natt = axis%natt + 1
492  endif
493  if( PRESENT(calendar) ) then
494  if (.NOT.cf_compliance) then
495  call mpp_write_meta( unit, axis%id, 'calendar', cval=axis%calendar)
496  else
497  call mpp_write_meta( unit, axis%id, 'calendar', cval=lowercase(axis%calendar))
498  endif
499  axis%natt = axis%natt + 1
500  endif
501  if( PRESENT(cartesian) ) then
502  if (.NOT.cf_compliance) then
503  call mpp_write_meta( unit, axis%id, 'cartesian_axis', cval=axis%cartesian)
504  axis%natt = axis%natt + 1
505  else
506  if (trim(axis%cartesian).ne.'N') then
507  call mpp_write_meta( unit, axis%id, 'axis', cval=axis%cartesian)
508  axis%natt = axis%natt + 1
509  endif
510  endif
511  endif
512  if( PRESENT(sense) )then
513  if( sense.EQ.-1 )then
514  call mpp_write_meta( unit, axis%id, 'positive', cval='down')
515  axis%natt = axis%natt + 1
516  else if( sense.EQ.1 )then
517  call mpp_write_meta( unit, axis%id, 'positive', cval='up')
518  axis%natt = axis%natt + 1
519  else
520  ! silently ignore values of sense other than +/-1.
521  end if
522  end if
523  if( PRESENT(min) ) then
524  call mpp_write_meta( unit, axis%id, 'valid_min', rval=min)
525  axis%natt = axis%natt + 1
526  endif
527  if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. domain_exist )then
528  call mpp_write_meta( unit, axis%id, 'domain_decomposition', ival=(/isg,ieg,is,ie/))
529  axis%natt = axis%natt + 1
530  end if
531  if( verbose )print '(a,2i6,x,a,2i3)', 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
532  pe, unit, trim(axis%name), axis%id, axis%did
533 
534  mpp_file(unit)%ndim = max(1,mpp_file(unit)%ndim + 1)
535 
536 ! call mpp_clock_end(mpp_write_clock)
537  return
538  end subroutine mpp_write_meta_axis_r1d
539 
540  subroutine mpp_write_meta_axis_i1d(unit, axis, name, units, longname, data, min, compressed)
541 !load the values in an axistype (still need to call mpp_write)
542 !write metadata attributes for axis
543 !it is declared intent(inout) so you can nullify pointers in the incoming object if needed
544 !the f90 standard doesn't guarantee that intent(out) on a type guarantees that its pointer components will be unassociated
545  integer, intent(in) :: unit
546  type(axistype), intent(inout) :: axis
547  character(len=*), intent(in) :: name, units, longname
548  integer, intent(in) :: data(:)
549  integer, intent(in), optional :: min
550  character(len=*), intent(in), optional :: compressed
551 
552  integer :: istat
553  logical :: domain_exist
554  type(domain2d), pointer :: io_domain => NULL()
555 
556 ! call mpp_clock_begin(mpp_write_clock)
557  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META_I1D: must first call mpp_io_init.' )
558  if( .NOT. mpp_file(unit)%write_on_this_pe) then
559 ! call mpp_clock_end(mpp_write_clock)
560  return
561  endif
562  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
563  if( mpp_file(unit)%initialized ) &
564  call mpp_error( FATAL, 'MPP_WRITE_META_I1D: cannot write metadata to file after an mpp_write.' )
565 
566 !pre-existing pointers need to be nullified
567  if( ASSOCIATED(axis%idata) ) then
568  DEALLOCATE(axis%idata, stat=istat)
569  endif
570 !load axistype
571  axis%name = name
572  axis%units = units
573  axis%longname = longname
574  if( PRESENT(compressed)) axis%compressed = trim(compressed)
575  axis%len = size(data(:))
576  allocate(axis%idata(axis%len))
577  axis%idata = data
578 !write metadata
579 #ifdef use_netCDF
580  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
581  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, axis%len, axis%did )
582  call netcdf_err( error, mpp_file(unit), axis )
583  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_INT, 1, axis%did, axis%id )
584  call netcdf_err( error, mpp_file(unit), axis )
585  else
586  call mpp_error( FATAL, 'MPP_WRITE_META_AXIS_I1D: Only netCDF format is currently supported.' )
587  end if
588 #endif
589 !write axis attributes
590  call mpp_write_meta( unit, axis%id, 'long_name', cval=axis%longname) ; axis%natt = axis%natt + 1
591  if (lowercase(trim(axis%units)).ne.'none' .OR. .NOT.cf_compliance) then
592  call mpp_write_meta( unit, axis%id, 'units', cval=axis%units) ; axis%natt = axis%natt + 1
593  endif
594  if( PRESENT(compressed) ) then
595  call mpp_write_meta( unit, axis%id, 'compress', cval=axis%compressed)
596  axis%natt = axis%natt + 1
597  endif
598  if( PRESENT(min) ) then
599  call mpp_write_meta( unit, axis%id, 'valid_min', ival=min)
600  axis%natt = axis%natt + 1
601  endif
602  if( verbose )print '(a,2i6,x,a,2i3)', 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
603  pe, unit, trim(axis%name), axis%id, axis%did
604 
605  mpp_file(unit)%ndim = max(1,mpp_file(unit)%ndim + 1)
606 
607 ! call mpp_clock_end(mpp_write_clock)
608  return
609  end subroutine mpp_write_meta_axis_i1d
610 
611 
612  subroutine mpp_write_meta_axis_unlimited(unit, axis, name, data, unlimited, units, longname)
613 !load the values in an axistype (still need to call mpp_write)
614 !write metadata attributes for axis
615 !it is declared intent(inout) so you can nullify pointers in the incoming object if needed
616 !the f90 standard doesn't guarantee that intent(out) on a type guarantees that its pointer components will be unassociated
617  integer, intent(in) :: unit
618  type(axistype), intent(inout) :: axis
619  character(len=*), intent(in) :: name
620  integer, intent(in) :: data ! Number of elements to be written
621  logical, intent(in) :: unlimited ! Provides unique arg signature
622  character(len=*), intent(in), optional :: units, longname
623 
624  integer :: istat
625  logical :: domain_exist
626  type(domain2d), pointer :: io_domain => NULL()
627 
628 ! call mpp_clock_begin(mpp_write_clock)
629  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META_I1D: must first call mpp_io_init.' )
630  if( .NOT. mpp_file(unit)%write_on_this_pe) then
631 ! call mpp_clock_end(mpp_write_clock)
632  return
633  endif
634  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
635  if( mpp_file(unit)%initialized ) &
636  call mpp_error( FATAL, 'MPP_WRITE_META_I1D: cannot write metadata to file after an mpp_write.' )
637 
638 !load axistype
639  axis%name = name
640  if(present(units)) axis%units = units
641  if(present(longname)) axis%longname = longname
642  axis%len = 1
643  allocate(axis%idata(1))
644  axis%idata = data
645 !write metadata
646 #ifdef use_netCDF
647  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
648  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, NF_UNLIMITED, axis%did )
649  call netcdf_err( error, mpp_file(unit), axis )
650  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_INT, 0, axis%did, axis%id )
651  call netcdf_err( error, mpp_file(unit), axis )
652  else
653  call mpp_error( FATAL, 'MPP_WRITE_META_AXIS_UNLIMITED: Only netCDF format is currently supported.' )
654  end if
655 #endif
656 !write axis attributes
657  if(present(longname)) then
658  call mpp_write_meta(unit,axis%id,'long_name',cval=axis%longname); axis%natt=axis%natt+1
659  endif
660  if(present(units)) then
661  if (lowercase(trim(axis%units)).ne.'none' .OR. .NOT.cf_compliance) then
662  call mpp_write_meta(unit,axis%id,'units', cval=axis%units); axis%natt=axis%natt+1
663  endif
664  endif
665  if( verbose )print '(a,2i6,x,a,2i3)', &
666  'MPP_WRITE_META_UNLIMITED: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
667  pe, unit, trim(axis%name), axis%id, axis%did
668 
669  mpp_file(unit)%ndim = max(1,mpp_file(unit)%ndim + 1)
670 
671 ! call mpp_clock_end(mpp_write_clock)
672  return
673  end subroutine mpp_write_meta_axis_unlimited
674 
675 
676  subroutine mpp_write_meta_field( unit, field, axes, name, units, longname,&
677  min, max, missing, fill, scale, add, pack, time_method, standard_name, checksum)
678 !define field: must have already called mpp_write_meta(axis) for each axis
679  integer, intent(in) :: unit
680  type(fieldtype), intent(inout) :: field
681  type(axistype), intent(in) :: axes(:)
682  character(len=*), intent(in) :: name, units, longname
683  real, intent(in), optional :: min, max, missing, fill, scale, add
684  integer, intent(in), optional :: pack
685  character(len=*), intent(in), optional :: time_method
686  character(len=*), intent(in), optional :: standard_name
687  integer(LONG_KIND), dimension(:), intent(in), optional :: checksum
688 !this array is required because of f77 binding on netCDF interface
689  integer, allocatable :: axis_id(:)
690  real :: a, b
691  integer :: i, istat, ishift, jshift
692  character(len=64) :: checksum_char
693 
694 ! call mpp_clock_begin(mpp_write_clock)
695 
696  !--- figure out the location of data, this is needed in mpp_write.
697  !--- for NON-symmetry domain, the position is not an issue.
698  !--- we may need to rethink how to address the symmetric issue.
699  ishift = 0; jshift = 0
700  do i = 1, size(axes(:))
701  select case ( lowercase( axes(i)%cartesian ) )
702  case ( 'x' )
703  ishift = axes(i)%shift
704  case ( 'y' )
705  jshift = axes(i)%shift
706  end select
707  end do
708 
709  field%position = CENTER
710  if(ishift == 1 .AND. jshift == 1) then
711  field%position = CORNER
712  else if(ishift == 1) then
713  field%position = EAST
714  else if(jshift == 1) then
715  field%position = NORTH
716  endif
717 
718  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
719 
720  if( .NOT.mpp_file(unit)%write_on_this_pe) then
721  if( .NOT. ASSOCIATED(field%axes) )allocate(field%axes(1)) !temporary fix
722 ! call mpp_clock_end(mpp_write_clock)
723  return
724  endif
725  if( .NOT.mpp_file(unit)%opened ) call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
726  if( mpp_file(unit)%initialized ) then
727 ! File has already been written to and needs to be returned to define mode.
728 #ifdef use_netCDF
729  error = NF_REDEF(mpp_file(unit)%ncid)
730 #endif
731  mpp_file(unit)%initialized = .false.
732  endif
733 ! call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
734 
735 !pre-existing pointers need to be nullified
736  if( ASSOCIATED(field%axes) ) DEALLOCATE(field%axes, stat=istat)
737  if( ASSOCIATED(field%size) ) DEALLOCATE(field%size, stat=istat)
738 !fill in field metadata
739  field%name = name
740  field%units = units
741  field%longname = longname
742  allocate( field%axes(size(axes(:))) )
743  field%axes = axes
744  field%ndim = size(axes(:))
745  field%time_axis_index = -1 !this value will never match any axis index
746 !size is buffer area for the corresponding axis info: it is required to buffer this info in the fieldtype
747 !because axis might be reused in different files
748  allocate( field%size(size(axes(:))) )
749  do i = 1,size(axes(:))
750  if( ASSOCIATED(axes(i)%data) )then !space axis
751  field%size(i) = size(axes(i)%data(:))
752  else !time
753  field%size(i) = 1
754  field%time_axis_index = i
755  end if
756  end do
757 !attributes
758  if( PRESENT(min) ) field%min = min
759  if( PRESENT(max) ) field%max = max
760  if( PRESENT(scale) ) field%scale = scale
761  if( PRESENT(add) ) field%add = add
762  if( PRESENT(standard_name)) field%standard_name = standard_name
763  if( PRESENT(missing) ) field%missing = missing
764  if( PRESENT(fill) ) field%fill = fill
765  field%checksum = 0
766  if( PRESENT(checksum) ) field%checksum(1:size(checksum)) = checksum(:)
767 
768  ! Issue warning if fill and missing are different
769  if ( (present(fill).and.present(missing)) .and. (field%missing .ne. field%fill) ) then
770  call mpp_error(WARNING, 'MPP_WRITE_META: NetCDF attributes _FillValue and missing_value should be equal.')
771  end if
772 !pack is currently used only for netCDF
773  field%pack = 2 !default write 32-bit floats
774  if( PRESENT(pack) )field%pack = pack
775  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
776 #ifdef use_netCDF
777  allocate( axis_id(size(field%axes(:))) )
778  do i = 1,size(field%axes(:))
779  axis_id(i) = field%axes(i)%did
780  end do
781 !write field def
782  select case (field%pack)
783  case(0)
784  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_INT, size(field%axes(:)), axis_id, field%id )
785  case(1)
786  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_DOUBLE, size(field%axes(:)), axis_id, field%id )
787  case(2)
788  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_FLOAT, size(field%axes(:)), axis_id, field%id )
789  case(4)
790  if( .NOT.PRESENT(scale) .OR. .NOT.PRESENT(add) ) &
791  call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=4.' )
792  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_SHORT, size(field%axes(:)), axis_id, field%id )
793  case(8)
794  if( .NOT.PRESENT(scale) .OR. .NOT.PRESENT(add) ) &
795  call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=8.' )
796  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_BYTE, size(field%axes(:)), axis_id, field%id )
797  case default
798  call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
799  end select
800  call netcdf_err( error, mpp_file(unit), field=field )
801  deallocate(axis_id)
802 #ifndef use_netCDF3
803  if(shuffle .NE. 0 .OR. deflate .NE. 0) then
804  error = NF_DEF_VAR_DEFLATE(mpp_file(unit)%ncid, field%id, shuffle, deflate, deflate_level)
805  call netcdf_err( error, mpp_file(unit), field=field )
806  endif
807 #endif
808 #endif
809  else
810  varnum = varnum + 1
811  field%id = varnum
812  if( PRESENT(pack) )call mpp_error( WARNING, 'MPP_WRITE_META: Packing is currently available only on netCDF files.' )
813 !write field def
814  write( text, '(a,i4,a)' )'FIELD ', field%id, ' name'
815  call write_attribute( unit, trim(text), cval=field%name )
816  write( text, '(a,i4,a)' )'FIELD ', field%id, ' axes'
817  call write_attribute( unit, trim(text), ival=field%axes(:)%did )
818  end if
819 !write field attributes: these names follow netCDF conventions
820  call mpp_write_meta( unit, field%id, 'long_name', cval=field%longname)
821  if (lowercase(trim(field%units)).ne.'none' .OR. .NOT.cf_compliance) then
822  call mpp_write_meta( unit, field%id, 'units', cval=field%units)
823  endif
824 !all real attributes must be written as packed
825  if( PRESENT(min) .AND. PRESENT(max) )then
826  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
827  call mpp_write_meta( unit, field%id, 'valid_range', rval=(/min,max/), pack=pack )
828  else
829  a = nint((min-add)/scale)
830  b = nint((max-add)/scale)
831  call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=pack )
832  end if
833  else if( PRESENT(min) )then
834  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
835  call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=pack )
836  else
837  a = nint((min-add)/scale)
838  call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=pack )
839  end if
840  else if( PRESENT(max) )then
841  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
842  call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=pack )
843  else
844  a = nint((max-add)/scale)
845  call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=pack )
846  end if
847  end if
848 ! write missing_value
849  if ( present(missing) ) then
850  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
851  call mpp_write_meta( unit, field%id, 'missing_value', rval=field%missing, pack=pack )
852  else
853  a = nint((missing-add)/scale)
854  call mpp_write_meta( unit, field%id, 'missing_value', rval=a, pack=pack )
855  end if
856  end if
857 ! write _FillValue
858  if ( present(fill) ) then
859  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
860  call mpp_write_meta( unit, field%id, '_FillValue', rval=field%fill, pack=pack )
861  else if (field%pack==0) then ! some safety checks for integer fills
862  if ( present(scale).OR.present(add) ) then
863  call mpp_error(FATAL,"add,scale not currently implimented for pack=0 int handling, try reals instead.")
864  else
865  ! Trust No One
866  call mpp_write_meta( unit, field%id, '_FillValue', ival=MPP_FILL_INT, pack=pack )
867  end if
868  else
869  a = nint((fill-add)/scale)
870  call mpp_write_meta( unit, field%id, '_FillValue', rval=a, pack=pack )
871  end if
872  end if
873 
874  if( field%pack.NE.1 .AND. field%pack.NE.2 )then
875  call mpp_write_meta( unit, field%id, 'packing', ival=field%pack )
876  if( PRESENT(scale) )call mpp_write_meta( unit, field%id, 'scale_factor', rval=field%scale )
877  if( PRESENT(add) )call mpp_write_meta( unit, field%id, 'add_offset', rval=field%add )
878  end if
879 
880  if( present(checksum) )then
881  write (checksum_char,'(Z16)') field%checksum(1)
882  do i = 2,size(checksum)
883  write (checksum_char,'(a,Z16)') trim(checksum_char)//",",checksum(i)
884  enddo
885  call mpp_write_meta( unit, field%id, 'checksum', cval=checksum_char )
886  end if
887 
888  if ( PRESENT(time_method) ) then
889  call mpp_write_meta(unit,field%id, 'cell_methods',cval='time: '//trim(time_method))
890  endif
891  if ( PRESENT(standard_name)) &
892  call mpp_write_meta(unit,field%id,'standard_name ', cval=field%standard_name)
893 
894  if( verbose )print '(a,2i6,x,a,i3)', 'MPP_WRITE_META: Wrote field metadata: pe, unit, field%name, field%id=', &
895  pe, unit, trim(field%name), field%id
896 
897 ! call mpp_clock_end(mpp_write_clock)
898  return
899  end subroutine mpp_write_meta_field
900 
901  subroutine write_attribute( unit, name, rval, ival, cval, pack )
902 !called to write metadata for non-netCDF I/O
903  integer, intent(in) :: unit
904  character(len=*), intent(in) :: name
905  real, intent(in), optional :: rval(:)
906  integer, intent(in), optional :: ival(:)
907  character(len=*), intent(in), optional :: cval
908 !pack is currently ignored in this routine: only used by netCDF I/O
909  integer, intent(in), optional :: pack
910 
911  if( mpp_file(unit)%nohdrs )return
912 !encode text string
913  if( PRESENT(rval) )then
914  write( text,* )trim(name)//'=', rval
915  else if( PRESENT(ival) )then
916  write( text,* )trim(name)//'=', ival
917  else if( PRESENT(cval) )then
918  text = ' '//trim(name)//'='//trim(cval)
919  else
920  call mpp_error( FATAL, 'WRITE_ATTRIBUTE: one of rval, ival, cval must be present.' )
921  end if
922  if( mpp_file(unit)%format.EQ.MPP_ASCII )then
923 !implies sequential access
924  write( unit,fmt='(a)' )trim(text)//char(10)
925  else !MPP_IEEE32 or MPP_NATIVE
926  if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
927  write(unit)trim(text)//char(10)
928  else !MPP_DIRECT
929  write( unit,rec=mpp_file(unit)%record )trim(text)//char(10)
930  if( verbose )print '(a,i6,a,i3)', 'WRITE_ATTRIBUTE: PE=', pe, ' wrote record ', mpp_file(unit)%record
931  mpp_file(unit)%record = mpp_file(unit)%record + 1
932  end if
933  end if
934  return
935  end subroutine write_attribute
936 
937  subroutine write_attribute_netcdf( unit, id, name, rval, ival, cval, pack )
938 !called to write metadata for netCDF I/O
939  integer, intent(in) :: unit
940  integer, intent(in) :: id
941  character(len=*), intent(in) :: name
942  real, intent(in), optional :: rval(:)
943  integer, intent(in), optional :: ival(:)
944  character(len=*), intent(in), optional :: cval
945  integer, intent(in), optional :: pack
946  integer, allocatable :: rval_i(:)
947 #ifdef use_netCDF
948  if( PRESENT(rval) )then
949 !pack was only meaningful for FP numbers, but is now extended by the ival branch of this routine
950  if( PRESENT(pack) )then
951  if( pack== 0 ) then !! here be dragons, use ival branch!...
952  if( KIND(rval).EQ.DOUBLE_KIND )then
953  call mpp_error( FATAL, &
954  'WRITE_ATTRIBUTE_NETCDF: attempting to write internal NF_INT, currently int32, as double.' )
955  error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_DOUBLE, size(rval(:)), rval )
956  else if( KIND(rval).EQ.FLOAT_KIND )then
957  call mpp_error( FATAL, &
958  'WRITE_ATTRIBUTE_NETCDF: attempting to write internal NF_INT, currently int32, as float.' )
959  error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_DOUBLE, size(rval(:)), rval )
960  end if
961  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
962  else if( pack.EQ.1 )then
963  if( KIND(rval).EQ.DOUBLE_KIND )then
964  error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_DOUBLE, size(rval(:)), rval )
965  else if( KIND(rval).EQ.FLOAT_KIND )then
966  call mpp_error( WARNING, &
967  'WRITE_ATTRIBUTE_NETCDF: attempting to write internal 32-bit real as external 64-bit.' )
968  error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_DOUBLE, size(rval(:)), rval )
969  end if
970  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
971  else if( pack.EQ.2 )then
972  if( KIND(rval).EQ.DOUBLE_KIND )then
973  error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval(:)), rval )
974  else if( KIND(rval).EQ.FLOAT_KIND )then
975  error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval(:)), rval )
976  end if
977  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
978  else if( pack.EQ.4 )then
979  allocate( rval_i(size(rval(:))) )
980  rval_i = rval
981  if( KIND(rval).EQ.DOUBLE_KIND )then
982  error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_SHORT, size(rval_i(:)), rval )
983  else if( KIND(rval).EQ.FLOAT_KIND )then
984  error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_SHORT, size(rval_i(:)), rval )
985  end if
986  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
987  deallocate(rval_i)
988  else if( pack.EQ.8 )then
989  allocate( rval_i(size(rval(:))) )
990  rval_i = rval
991  if( KIND(rval).EQ.DOUBLE_KIND )then
992  error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_BYTE, size(rval_i(:)), rval )
993  else if( KIND(rval).EQ.FLOAT_KIND )then
994  error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_BYTE, size(rval_i(:)), rval )
995  end if
996  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
997  deallocate(rval_i)
998  else
999  call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: only legal packing values are 1,2,4,8.' )
1000  end if
1001  else
1002 !default is to write FLOATs (32-bit)
1003  if( KIND(rval).EQ.DOUBLE_KIND )then
1004  error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval(:)), rval )
1005  else if( KIND(rval).EQ.FLOAT_KIND )then
1006  error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval(:)), rval )
1007  end if
1008  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
1009  end if
1010  else if( PRESENT(ival) )then
1011  if( PRESENT(pack) ) then
1012  if (pack ==0) then
1013  if (KIND(ival).EQ.LONG_KIND ) then
1014  call mpp_error(FATAL,'only use NF_INTs with pack=0 for now')
1015  end if
1016  error = NF_PUT_ATT_INT( mpp_file(unit)%ncid, id, name, NF_INT, size(ival(:)), ival ) !!XXX int32_t..
1017  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
1018  else
1019  call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: only implimented ints when pack=0, else use reals.' )
1020  endif
1021  else
1022  error = NF_PUT_ATT_INT ( mpp_file(unit)%ncid, id, name, NF_INT, size(ival(:)), ival )
1023  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
1024  end if
1025  else if( present(cval) )then
1026  if (.NOT.cf_compliance .or. trim(name).NE.'calendar') then
1027  error = NF_PUT_ATT_TEXT( mpp_file(unit)%ncid, id, name, len_trim(cval), cval )
1028  else
1029  error = NF_PUT_ATT_TEXT( mpp_file(unit)%ncid, id, name, len_trim(cval), lowercase(cval) )
1030  endif
1031  call netcdf_err( error, mpp_file(unit), string=' Attribute='//name )
1032  else
1033  call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: one of rval, ival, cval must be present.' )
1034  end if
1035 #endif /* use_netCDF */
1036  return
1037  end subroutine write_attribute_netcdf
1038 
1039 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1040 ! !
1041 ! MPP_WRITE !
1042 ! !
1043 ! mpp_write is used to write data to the file on <unit> using the !
1044 ! file parameters supplied by mpp_open(). Axis and field definitions !
1045 ! must have previously been written to the file using mpp_write_meta. !
1046 ! !
1047 ! mpp_write can take 2 forms, one for distributed data and one for !
1048 ! non-distributed data. Distributed data refer to arrays whose two !
1049 ! fastest-varying indices are domain-decomposed. Distributed data !
1050 ! must be 2D or 3D (in space). Non-distributed data can be 0-3D. !
1051 ! !
1052 ! In all calls to mpp_write, tstamp is an optional argument. It is to !
1053 ! be omitted if the field was defined not to be a function of time. !
1054 ! Results are unpredictable if the argument is supplied for a time- !
1055 ! independent field, or omitted for a time-dependent field. Repeated !
1056 ! writes of a time-independent field are also not recommended. One !
1057 ! time level of one field is written per call. !
1058 ! !
1059 ! !
1060 ! For non-distributed data, use !
1061 ! !
1062 ! mpp_write( unit, field, data, tstamp ) !
1063 ! integer, intent(in) :: unit !
1064 ! type(fieldtype), intent(in) :: field !
1065 ! real(DOUBLE_KIND), optional :: tstamp !
1066 ! data is real and can be scalar or of rank 1-3. !
1067 ! !
1068 ! For distributed data, use !
1069 ! !
1070 ! mpp_write( unit, field, domain, data, tstamp ) !
1071 ! integer, intent(in) :: unit !
1072 ! type(fieldtype), intent(in) :: field !
1073 ! type(domain2D), intent(in) :: domain !
1074 ! real(DOUBLE_KIND), optional :: tstamp !
1075 ! data is real and can be of rank 2 or 3. !
1076 ! !
1077 ! mpp_write( unit, axis ) !
1078 ! integer, intent(in) :: unit !
1079 ! type(axistype), intent(in) :: axis !
1080 ! !
1081 ! This call writes the actual co-ordinate values along each space !
1082 ! axis. It must be called once for each space axis after all other !
1083 ! metadata has been written. !
1084 ! !
1085 ! The mpp_write package also includes the routine write_record which !
1086 ! performs the actual write. This routine is private to this module. !
1087 ! !
1088 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1089 #undef WRITE_RECORD_
1090 #define WRITE_RECORD_ write_record_default
1091 #undef MPP_WRITE_2DDECOMP_2D_
1092 #define MPP_WRITE_2DDECOMP_2D_ mpp_write_2ddecomp_r2d
1093 #undef MPP_WRITE_2DDECOMP_3D_
1094 #define MPP_WRITE_2DDECOMP_3D_ mpp_write_2ddecomp_r3d
1095 #undef MPP_WRITE_2DDECOMP_4D_
1096 #define MPP_WRITE_2DDECOMP_4D_ mpp_write_2ddecomp_r4d
1097 #undef MPP_TYPE_
1098 #define MPP_TYPE_ real
1099 #include <mpp_write_2Ddecomp.h>
1100 
1101 #ifdef OVERLOAD_R8
1102 #define WRITE_RECORD_ write_record_r8
1103 #undef MPP_WRITE_2DDECOMP_2D_
1104 #undef MPP_WRITE_2DDECOMP_2D_
1105 #define MPP_WRITE_2DDECOMP_2D_ mpp_write_2ddecomp_r2d_r8
1106 #undef MPP_WRITE_2DDECOMP_3D_
1107 #define MPP_WRITE_2DDECOMP_3D_ mpp_write_2ddecomp_r3d_r8
1108 #undef MPP_WRITE_2DDECOMP_4D_
1109 #define MPP_WRITE_2DDECOMP_4D_ mpp_write_2ddecomp_r4d_r8
1110 #undef MPP_TYPE_
1111 #define MPP_TYPE_ real(DOUBLE_KIND)
1112 #include <mpp_write_2Ddecomp.h>
1113 #endif
1114 
1115 #undef MPP_WRITE_COMPRESSED_1D_
1116 #define MPP_WRITE_COMPRESSED_1D_ mpp_write_compressed_r1d
1117 #undef MPP_WRITE_COMPRESSED_2D_
1118 #define MPP_WRITE_COMPRESSED_2D_ mpp_write_compressed_r2d
1119 #undef MPP_WRITE_COMPRESSED_3D_
1120 #define MPP_WRITE_COMPRESSED_3D_ mpp_write_compressed_r3d
1121 #undef MPP_TYPE_
1122 #define MPP_TYPE_ real
1123 #include <mpp_write_compressed.h>
1124 
1125 #undef MPP_WRITE_UNLIMITED_AXIS_1D_
1126 #define MPP_WRITE_UNLIMITED_AXIS_1D_ mpp_write_unlimited_axis_r1d
1127 #undef MPP_TYPE_
1128 #define MPP_TYPE_ real
1129 #include <mpp_write_unlimited_axis.h>
1130 
1131 #undef MPP_WRITE_
1132 #define MPP_WRITE_ mpp_write_r0D
1133 #undef MPP_TYPE_
1134 #define MPP_TYPE_ real
1135 #undef MPP_RANK_
1136 #define MPP_RANK_ !
1137 #undef MPP_WRITE_RECORD_
1138 #define MPP_WRITE_RECORD_ call write_record_default( unit, field, 1, (/data/), tstamp)
1139 #include <mpp_write.h>
1140 
1141 #undef MPP_WRITE_
1142 #define MPP_WRITE_ mpp_write_r1D
1143 #undef MPP_TYPE_
1144 #define MPP_TYPE_ real
1145 #undef MPP_WRITE_RECORD_
1146 #define MPP_WRITE_RECORD_ call write_record_default( unit, field, size(data(:)), data, tstamp)
1147 #undef MPP_RANK_
1148 #define MPP_RANK_ (:)
1149 #include <mpp_write.h>
1150 
1151 #undef MPP_WRITE_
1152 #define MPP_WRITE_ mpp_write_r2D
1153 #undef MPP_TYPE_
1154 #define MPP_TYPE_ real
1155 #undef MPP_WRITE_RECORD_
1156 #define MPP_WRITE_RECORD_ call write_record_default( unit, field, size(data(:,:)), data, tstamp )
1157 #undef MPP_RANK_
1158 #define MPP_RANK_ (:,:)
1159 #include <mpp_write.h>
1160 
1161 #undef MPP_WRITE_
1162 #define MPP_WRITE_ mpp_write_r3D
1163 #undef MPP_TYPE_
1164 #define MPP_TYPE_ real
1165 #undef MPP_WRITE_RECORD_
1166 #define MPP_WRITE_RECORD_ call write_record_default( unit, field, size(data(:,:,:)), data, tstamp)
1167 #undef MPP_RANK_
1168 #define MPP_RANK_ (:,:,:)
1169 #include <mpp_write.h>
1170 
1171 #undef MPP_WRITE_
1172 #define MPP_WRITE_ mpp_write_r4D
1173 #undef MPP_TYPE_
1174 #define MPP_TYPE_ real
1175 #undef MPP_WRITE_RECORD_
1176 #define MPP_WRITE_RECORD_ call write_record_default( unit, field, size(data(:,:,:,:)), data, tstamp)
1177 #undef MPP_RANK_
1178 #define MPP_RANK_ (:,:,:,:)
1179 #include <mpp_write.h>
1180 
1181  subroutine mpp_write_axis( unit, axis )
1182  integer, intent(in) :: unit
1183  type(axistype), intent(in) :: axis
1184  type(fieldtype) :: field
1185 
1186  call mpp_clock_begin(mpp_write_clock)
1187  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
1188  if( .NOT. mpp_file(unit)%write_on_this_pe ) then
1189  call mpp_clock_end(mpp_write_clock)
1190  return
1191  endif
1192  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
1193 !we convert axis to type(fieldtype) in order to call write_record
1194  field = default_field
1195  allocate( field%axes(1) )
1196  field%axes(1) = axis
1197  allocate( field%size(1) )
1198  field%size(1) = axis%len
1199  field%id = axis%id
1200 
1201  field%name = axis%name
1202  field%longname = axis%longname
1203  field%units = axis%units
1204 
1205  if(ASSOCIATED(axis%data))then
1206  allocate( field%axes(1)%data(size(axis%data) ))
1207  field%axes(1)%data = axis%data
1208  call write_record( unit, field, axis%len, axis%data )
1209  elseif(ASSOCIATED(axis%idata))then
1210  allocate( field%axes(1)%data(size(axis%idata) ))
1211  field%axes(1)%data = REAL(axis%idata)
1212  field%pack=4
1213  call write_record( unit, field, axis%len, REAL(axis%idata) )
1214  else
1215  call mpp_error( FATAL, 'MPP_WRITE_AXIS: No data associated with axis.' )
1216  endif
1217 
1218  deallocate(field%axes(1)%data)
1219  deallocate(field%axes,field%size)
1220 
1221  call mpp_clock_end(mpp_write_clock)
1222  return
1223  end subroutine mpp_write_axis
1224 
1225 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1226 ! !
1227 ! MPP_COPY_META !
1228 ! !
1229 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1230  subroutine mpp_copy_meta_global( unit, gatt )
1231 !writes a global metadata attribute to unit <unit>
1232 !attribute <name> can be an real, integer or character
1233 !one and only one of rval, ival, and cval should be present
1234 !the first found will be used
1235 !for a non-netCDF file, it is encoded into a string "GLOBAL <name> <val>"
1236  integer, intent(in) :: unit
1237  type(atttype), intent(in) :: gatt
1238  integer :: len, error
1239 
1240  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
1241  if( .NOT. mpp_file(unit)%write_on_this_pe )return
1242  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
1243  if( mpp_file(unit)%initialized ) then
1244 ! File has already been written to and needs to be returned to define mode.
1245 #ifdef use_netCDF
1246  error = NF_REDEF(mpp_file(unit)%ncid)
1247 #endif
1248  mpp_file(unit)%initialized = .false.
1249  endif
1250 ! call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
1251 #ifdef use_netCDF
1252  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
1253  if( gatt%type.EQ.NF_CHAR )then
1254  len = gatt%len
1255  call write_attribute_netcdf( unit, NF_GLOBAL, gatt%name, cval=gatt%catt(1:len) )
1256  else
1257  call write_attribute_netcdf( unit, NF_GLOBAL, gatt%name, rval=gatt%fatt )
1258  endif
1259  else
1260  if( gatt%type.EQ.NF_CHAR )then
1261  len=gatt%len
1262  call write_attribute( unit, 'GLOBAL '//trim(gatt%name), cval=gatt%catt(1:len) )
1263  else
1264  call write_attribute( unit, 'GLOBAL '//trim(gatt%name), rval=gatt%fatt )
1265  endif
1266  end if
1267 #else
1268  call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
1269 #endif
1270  return
1271  end subroutine mpp_copy_meta_global
1272 
1273  subroutine mpp_copy_meta_axis( unit, axis, domain )
1274 !load the values in an axistype (still need to call mpp_write)
1275 !write metadata attributes for axis. axis is declared inout
1276 !because the variable and dimension ids are altered
1277 
1278  integer, intent(in) :: unit
1279  type(axistype), intent(inout) :: axis
1280  type(domain1D), intent(in), optional :: domain
1281  character(len=512) :: text
1282  integer :: i, len, is, ie, isg, ieg, error
1283 
1284 ! call mpp_clock_begin(mpp_write_clock)
1285  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
1286  if( .NOT. mpp_file(unit)%write_on_this_pe ) then
1287 ! call mpp_clock_end(mpp_write_clock)
1288  return
1289  endif
1290  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
1291  if( mpp_file(unit)%initialized ) then
1292 ! File has already been written to and needs to be returned to define mode.
1293 #ifdef use_netCDF
1294  error = NF_REDEF(mpp_file(unit)%ncid)
1295 #endif
1296  mpp_file(unit)%initialized = .false.
1297  endif
1298 ! call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
1299 
1300 ! redefine domain if present
1301  if( PRESENT(domain) )then
1302  axis%domain = domain
1303  else
1304  axis%domain = NULL_DOMAIN1D
1305  end if
1306 
1307 #ifdef use_netCDF
1308 !write metadata
1309  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
1310 
1311 !write axis def
1312  if( ASSOCIATED(axis%data) )then !space axis
1313  if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
1314  call mpp_get_compute_domain( axis%domain, is, ie )
1315  call mpp_get_global_domain( axis%domain, isg, ieg )
1316  ie = ie + axis%shift
1317  ieg = ieg + axis%shift
1318  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, ie-is+1, axis%did )
1319  else
1320  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, size(axis%data(:)), axis%did )
1321  end if
1322  call netcdf_err( error, mpp_file(unit), axis )
1323  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id )
1324  call netcdf_err( error, mpp_file(unit), axis )
1325  else !time axis
1326  error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, NF_UNLIMITED, axis%did )
1327  call netcdf_err( error, mpp_file(unit), axis )
1328  error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id )
1329  call netcdf_err( error, mpp_file(unit), axis )
1330  mpp_file(unit)%id = axis%id !file ID is the same as time axis varID
1331  mpp_file(unit)%recdimid = axis%did ! record dimension id
1332  end if
1333  else
1334  varnum = varnum + 1
1335  axis%id = varnum
1336  axis%did = varnum
1337 !write axis def
1338  write( text, '(a,i4,a)' )'AXIS ', axis%id, ' name'
1339  call write_attribute( unit, trim(text), cval=axis%name )
1340  write( text, '(a,i4,a)' )'AXIS ', axis%id, ' size'
1341  if( ASSOCIATED(axis%data) )then !space axis
1342  if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
1343  call mpp_get_compute_domain(axis%domain, is, ie)
1344  call write_attribute( unit, trim(text), ival=(/ie-is+1/) ) ! ??? is, ie is not initialized
1345  else
1346  call write_attribute( unit, trim(text), ival=(/size(axis%data(:))/) )
1347  end if
1348  else !time axis
1349  if( mpp_file(unit)%id.NE.-1 ) &
1350  call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
1351  call write_attribute( unit, trim(text), ival=(/0/) ) !a size of 0 indicates time axis
1352  mpp_file(unit)%id = axis%id
1353  end if
1354  end if
1355 !write axis attributes
1356 
1357  do i=1,axis%natt
1358  if( axis%Att(i)%name.NE.default_att%name )then
1359  if( axis%Att(i)%type.EQ.NF_CHAR )then
1360  len = axis%Att(i)%len
1361  call mpp_write_meta( unit, axis%id, axis%Att(i)%name, cval=axis%Att(i)%catt(1:len) )
1362  else
1363  call mpp_write_meta( unit, axis%id, axis%Att(i)%name, rval=axis%Att(i)%fatt)
1364  endif
1365  endif
1366  enddo
1367 
1368  if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
1369  call mpp_write_meta( unit, axis%id, 'domain_decomposition', ival=(/isg,ieg,is,ie/) )
1370  end if
1371  if( verbose )print '(a,2i6,x,a,2i3)', 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
1372  pe, unit, trim(axis%name), axis%id, axis%did
1373 #else
1374  call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
1375 #endif
1376 ! call mpp_clock_end(mpp_write_clock)
1377  return
1378  end subroutine mpp_copy_meta_axis
1379 
1380  subroutine mpp_copy_meta_field( unit, field, axes )
1381 !useful for copying field metadata from a previous call to mpp_read_meta
1382 !define field: must have already called mpp_write_meta(axis) for each axis
1383  integer, intent(in) :: unit
1384  type(fieldtype), intent(inout) :: field
1385  type(axistype), intent(in), optional :: axes(:)
1386 !this array is required because of f77 binding on netCDF interface
1387  integer, allocatable :: axis_id(:)
1388  real :: a, b
1389  integer :: i, error
1390 
1391 ! call mpp_clock_begin(mpp_write_clock)
1392  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
1393  if( .NOT. mpp_file(unit)%write_on_this_pe ) then
1394 ! call mpp_clock_end(mpp_write_clock)
1395  return
1396  endif
1397  if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
1398  if( mpp_file(unit)%initialized ) then
1399 ! File has already been written to and needs to be returned to define mode.
1400 #ifdef use_netCDF
1401  error = NF_REDEF(mpp_file(unit)%ncid)
1402 #endif
1403  mpp_file(unit)%initialized = .false.
1404  endif
1405 ! call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
1406 
1407  if( field%pack.NE.1 .AND. field%pack.NE.2 )then
1408  if( field%pack.NE.4 .AND. field%pack.NE.8 ) &
1409  call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
1410  end if
1411 
1412  if (PRESENT(axes)) then
1413  deallocate(field%axes)
1414  deallocate(field%size)
1415  allocate(field%axes(size(axes(:))))
1416  allocate(field%size(size(axes(:))))
1417  field%axes = axes
1418  do i=1,size(axes(:))
1419  if (ASSOCIATED(axes(i)%data)) then
1420  field%size(i) = size(axes(i)%data(:))
1421  else
1422  field%size(i) = 1
1423  field%time_axis_index = i
1424  endif
1425  enddo
1426  endif
1427 
1428  if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
1429 #ifdef use_netCDF
1430  allocate( axis_id(size(field%axes(:))) )
1431  do i = 1,size(field%axes(:))
1432  axis_id(i) = field%axes(i)%did
1433  end do
1434 !write field def
1435  select case (field%pack)
1436  case(1)
1437  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_DOUBLE, size(field%axes(:)), axis_id, field%id )
1438  case(2)
1439  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_FLOAT, size(field%axes(:)), axis_id, field%id )
1440  case(4)
1441 ! if( field%scale.EQ.default_field%scale .OR. field%add.EQ.default_field%add ) &
1442 ! call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=4.' )
1443  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_SHORT, size(field%axes(:)), axis_id, field%id )
1444  case(8)
1445 ! if( field%scale.EQ.default_field%scale .OR. field%add.EQ.default_field%add ) &
1446 ! call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=8.' )
1447  error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_BYTE, size(field%axes(:)), axis_id, field%id )
1448  case default
1449  call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
1450  end select
1451  deallocate( axis_id )
1452 #endif
1453  else
1454  varnum = varnum + 1
1455  field%id = varnum
1456  if( field%pack.NE.default_field%pack ) &
1457  call mpp_error( WARNING, 'MPP_WRITE_META: Packing is currently available only on netCDF files.' )
1458 !write field def
1459  write( text, '(a,i4,a)' )'FIELD ', field%id, ' name'
1460  call write_attribute( unit, trim(text), cval=field%name )
1461  write( text, '(a,i4,a)' )'FIELD ', field%id, ' axes'
1462  call write_attribute( unit, trim(text), ival=field%axes(:)%did )
1463  end if
1464 !write field attributes: these names follow netCDF conventions
1465  call mpp_write_meta( unit, field%id, 'long_name', cval=field%longname )
1466  if (lowercase(trim(field%units)).ne.'none' .OR. .NOT.cf_compliance) then
1467  call mpp_write_meta( unit, field%id, 'units', cval=field%units )
1468  endif
1469 !all real attributes must be written as packed
1470  if( (field%min.NE.default_field%min) .AND. (field%max.NE.default_field%max) )then
1471  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
1472  call mpp_write_meta( unit, field%id, 'valid_range', rval=(/field%min,field%max/), pack=field%pack )
1473  else
1474  a = nint((field%min-field%add)/field%scale)
1475  b = nint((field%max-field%add)/field%scale)
1476  call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=field%pack )
1477  end if
1478  else if( field%min.NE.default_field%min )then
1479  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
1480  call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=field%pack )
1481  else
1482  a = nint((field%min-field%add)/field%scale)
1483  call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=field%pack )
1484  end if
1485  else if( field%max.NE.default_field%max )then
1486  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
1487  call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=field%pack )
1488  else
1489  a = nint((field%max-field%add)/field%scale)
1490  call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=field%pack )
1491  end if
1492  end if
1493  if( field%missing.NE.default_field%missing )then
1494  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
1495  call mpp_write_meta( unit, field%id, 'missing_value', rval=field%missing, pack=field%pack )
1496  else
1497  a = nint((field%missing-field%add)/field%scale)
1498  call mpp_write_meta( unit, field%id, 'missing_value', rval=a, pack=field%pack )
1499  end if
1500  end if
1501  if( field%fill.NE.default_field%fill )then
1502  if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
1503  call mpp_write_meta( unit, field%id, '_FillValue', rval=field%missing, pack=field%pack )
1504  else
1505  a = nint((field%fill-field%add)/field%scale)
1506  call mpp_write_meta( unit, field%id, '_FillValue', rval=a, pack=field%pack )
1507  end if
1508  end if
1509  if( field%pack.NE.1 .AND. field%pack.NE.2 )then
1510  call mpp_write_meta( unit, field%id, 'packing', ival=field%pack )
1511  if( field%scale.NE.default_field%scale )call mpp_write_meta( unit, field%id, 'scale_factor', rval=field%scale )
1512  if( field%add.NE.default_field%add )call mpp_write_meta( unit, field%id, 'add_offset', rval=field%add )
1513  end if
1514  if( verbose )print '(a,2i6,x,a,i3)', 'MPP_WRITE_META: Wrote field metadata: pe, unit, field%name, field%id=', &
1515  pe, unit, trim(field%name), field%id
1516 
1517 ! call mpp_clock_end(mpp_write_clock)
1518  return
1519  end subroutine mpp_copy_meta_field
1520 
1521  subroutine mpp_modify_axis_meta( axis, name, units, longname, cartesian, data )
1522 
1523  type(axistype), intent(inout) :: axis
1524  character(len=*), intent(in), optional :: name, units, longname, cartesian
1525  real, dimension(:), intent(in), optional :: data
1526 
1527  if (PRESENT(name)) axis%name = trim(name)
1528  if (PRESENT(units)) axis%units = trim(units)
1529  if (PRESENT(longname)) axis%longname = trim(longname)
1530  if (PRESENT(cartesian)) axis%cartesian = trim(cartesian)
1531  if (PRESENT(data)) then
1532  axis%len = size(data(:))
1533  if (ASSOCIATED(axis%data)) deallocate(axis%data)
1534  allocate(axis%data(axis%len))
1535  axis%data = data
1536  endif
1537 
1538  return
1539  end subroutine mpp_modify_axis_meta
1540 
1541  subroutine mpp_modify_field_meta( field, name, units, longname, min, max, missing, axes )
1542 
1543  type(fieldtype), intent(inout) :: field
1544  character(len=*), intent(in), optional :: name, units, longname
1545  real, intent(in), optional :: min, max, missing
1546  type(axistype), dimension(:), intent(inout), optional :: axes
1547 
1548  if (PRESENT(name)) field%name = trim(name)
1549  if (PRESENT(units)) field%units = trim(units)
1550  if (PRESENT(longname)) field%longname = trim(longname)
1551  if (PRESENT(min)) field%min = min
1552  if (PRESENT(max)) field%max = max
1553  if (PRESENT(missing)) field%missing = missing
1554 ! if (PRESENT(axes)) then
1555 ! axis%len = size(data(:))
1556 ! deallocate(axis%data)
1557 ! allocate(axis%data(axis%len))
1558 ! axis%data = data
1559 ! endif
1560 
1561  return
1562  end subroutine mpp_modify_field_meta
************************************************************************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 a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version will
type(ext_fieldtype), dimension(:), pointer, save, private field
integer mpp_write_clock
Definition: mpp_io.F90:1054
*f90 *************************************************************************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:! ***********************************************************************subroutine MPP_UPDATE_NEST_FINE_2D_(field, nest_domain, wbuffer, ebuffer, sbuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_ ::wbuffer3D(size(wbuffer, 1), size(wbuffer, 2), 1) MPP_TYPE_ ::ebuffer3D(size(ebuffer, 1), size(ebuffer, 2), 1) MPP_TYPE_ ::sbuffer3D(size(sbuffer, 1), size(sbuffer, 2), 1) MPP_TYPE_ ::nbuffer3D(size(nbuffer, 1), size(nbuffer, 2), 1) pointer(ptr, field3D) pointer(ptr_w, wbuffer3D) pointer(ptr_e, ebuffer3D) pointer(ptr_s, sbuffer3D) pointer(ptr_n, nbuffer3D) ptr=LOC(field) ptr_w=LOC(wbuffer) ptr_e=LOC(ebuffer) ptr_s=LOC(sbuffer) ptr_n=LOC(nbuffer) call mpp_update_nest_fine(field3D, nest_domain, wbuffer3D, ebuffer3D, sbuffer3D, nbuffer3D, &flags, complete, position, extra_halo, name, tile_count) returnend subroutine MPP_UPDATE_NEST_FINE_2D_subroutine MPP_UPDATE_NEST_FINE_3D_(field, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::d_type type(nestSpec), pointer ::update=> set_mismatch integer ::tile update_position nbuffersz l_size integer
l_size ! loop over number of fields ke do je do ie to PE
integer natt
No description.
************************************************************************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:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> unit
character(len=1), parameter equal
subroutine, public add(value, cumul, num, wgt)
Definition: tools_func.F90:185
dictionary attributes
Definition: plotDiffs.py:16
integer, parameter, public up
subroutine, public copy(self, rhs)
************************************************************************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 a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT end
character(len=256) text
Definition: mpp_io.F90:1051
type(field_mgr_type), dimension(max_fields), private fields
*f90 *************************************************************************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:! ***********************************************************************! this routine is used to retrieve scalar boundary data for symmetric domain. subroutine MPP_GET_BOUNDARY_2D_(field, domain, ebuffer, sbuffer, wbuffer, nbuffer, flags, &position, complete, tile_count) type(domain2D), intent(in) ::domain MPP_TYPE_, intent(in) ::field(:,:) MPP_TYPE_, intent(inout), optional ::ebuffer(:), sbuffer(:), wbuffer(:), nbuffer(:) integer, intent(in), optional ::flags, position, tile_count logical, intent(in), optional ::complete MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_, allocatable, dimension(:,:) ::ebuffer2D, sbuffer2D, wbuffer2D, nbuffer2D integer ::xcount, ycount integer ::ntile logical ::need_ebuffer, need_sbuffer, need_wbuffer, need_nbuffer integer(LONG_KIND), dimension(MAX_DOMAIN_FIELDS, MAX_TILES), save ::f_addrs=-9999 integer(LONG_KIND), dimension(4, MAX_DOMAIN_FIELDS, MAX_TILES), save ::b_addrs=-9999 integer, save ::bsize(4)=0, isize=0, jsize=0, ksize=0, pos, list=0, l_size=0, upflags integer ::buffer_size(4) integer ::max_ntile, tile, update_position, ishift, jshift logical ::do_update, is_complete, set_mismatch character(len=3) ::text MPP_TYPE_ ::d_type type(overlapSpec), pointer ::bound=> NULL() ntile
character(len=32) units
No description.
type(diag_axis_type), dimension(:), allocatable, save axes
Definition: diag_axis.F90:80
integer, parameter, public none
character(len=32) name
l_size ! loop over number of fields ke do je do ie to je n if(.NOT. d_comm%R_do_buf(list)) cycle from_pe
logical module_is_initialized
integer(i_long) ncid
Definition: ncdw_state.f90:8
character(len=128) version
l_size ! loop over number of fields ke do je do ie to is
type
Definition: c2f.py:15
integer, parameter, public global
type(file_type), dimension(:), allocatable, save files
Definition: diag_data.F90:780
************************************************************************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:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> mpp_file(unit)%id
subroutine, public info(self)
************************************************************************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
integer error
Definition: mpp.F90:1310
integer, parameter, public down
************************************************************************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:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> id
subroutine calendar(year, month, day, hour)
real, dimension(maxmts) height
integer sense
No description.
logical, pointer fill
enddo ! cludge for now
real(double), parameter one
logical function received(this, seqno)
integer form
Definition: fms_io.F90:484
************************************************************************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:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
************************************************************************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 a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version and mpp_transmit will remain !backward compatible intent(inout) a
#define max(a, b)
Definition: mosaic_util.h:33
*f90 *************************************************************************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:! ***********************************************************************subroutine MPP_UPDATE_NEST_FINE_2D_(field, nest_domain, wbuffer, ebuffer, sbuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_ ::wbuffer3D(size(wbuffer, 1), size(wbuffer, 2), 1) MPP_TYPE_ ::ebuffer3D(size(ebuffer, 1), size(ebuffer, 2), 1) MPP_TYPE_ ::sbuffer3D(size(sbuffer, 1), size(sbuffer, 2), 1) MPP_TYPE_ ::nbuffer3D(size(nbuffer, 1), size(nbuffer, 2), 1) pointer(ptr, field3D) pointer(ptr_w, wbuffer3D) pointer(ptr_e, ebuffer3D) pointer(ptr_s, sbuffer3D) pointer(ptr_n, nbuffer3D) ptr=LOC(field) ptr_w=LOC(wbuffer) ptr_e=LOC(ebuffer) ptr_s=LOC(sbuffer) ptr_n=LOC(nbuffer) call mpp_update_nest_fine(field3D, nest_domain, wbuffer3D, ebuffer3D, sbuffer3D, nbuffer3D, &flags, complete, position, extra_halo, name, tile_count) returnend subroutine MPP_UPDATE_NEST_FINE_2D_subroutine MPP_UPDATE_NEST_FINE_3D_(field, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::d_type type(nestSpec), pointer ::update=> dimension(MAX_DOMAIN_FIELDS)
character(len=1), parameter space
************************************************************************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 a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version and mpp_transmit will remain !backward compatible intent(inout) i6
real(r8), dimension(cast_m, cast_n) t
************************************************************************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 a get means do a wait to ensure put on remote PE is complete stat
*f90 *************************************************************************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 not
real missing_value
No description.
#define min(a, b)
Definition: mosaic_util.h:32
integer header_buffer_val
Definition: mpp_io.F90:1059
real(fp), parameter scale_factor
Definition: Ellison.f90:65
real per
Longitude of perihelion with respect to autumnal equinox in NH [degrees].
Definition: astronomy.F90:345
character(len=32) format
Definition: fms_io.F90:535
character(len=len(cs)) function lowercase(cs)
Definition: oda_core.F90:1415
module
Definition: c2f.py:21
integer, parameter, public information
integer ndim
No description.