FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
mpp_io_util.inc
1! -*-f90-*-
2!***********************************************************************
3!* GNU Lesser General Public License
4!*
5!* This file is part of the GFDL Flexible Modeling System (FMS).
6!*
7!* FMS is free software: you can redistribute it and/or modify it under
8!* the terms of the GNU Lesser General Public License as published by
9!* the Free Software Foundation, either version 3 of the License, or (at
10!* your option) any later version.
11!*
12!* FMS is distributed in the hope that it will be useful, but WITHOUT
13!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15!* for more details.
16!*
17!* You should have received a copy of the GNU Lesser General Public
18!* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
19!***********************************************************************
20!> @file
21!> @brief Routines to retrieve data used in @ref mpp_io_mod
22
23!> @addtogroup mpp_io_mod
24!> @{
25
26 !> @brief Get some general information about a file.
27 !!
28 !> <br>Example usage:
29 !! @code{.F90}
30 !! call mpp_get_info( unit, ndim, nvar, natt, ntime )
31 !! @endcode
32 subroutine mpp_get_info( unit, ndim, nvar, natt, ntime )
33
34 integer, intent(in) :: unit
35 integer, intent(out) :: ndim, nvar, natt, ntime
36
37
38 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_INFO: must first call mpp_io_init.' )
39 if( .NOT.mpp_file(unit)%opened )&
40 call mpp_error(fatal, 'MPP_GET_INFO: invalid unit number, file '//trim(mpp_file(unit)%name))
41
42 ndim = mpp_file(unit)%ndim
43 nvar = mpp_file(unit)%nvar
44 natt = mpp_file(unit)%natt
45 ntime = mpp_file(unit)%time_level
46
47 return
48
49 end subroutine mpp_get_info
50
51 !> @brief Copy global file attributes for use by user
52 subroutine mpp_get_global_atts( unit, global_atts )
53
54 integer, intent(in) :: unit
55 type(atttype), intent(inout) :: global_atts(:) !< an attribute type which is allocated from the
56 !! calling routine
57
58 integer :: natt,i
59
60 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_INFO: must first call mpp_io_init.' )
61 if( .NOT.mpp_file(unit)%opened )&
62 call mpp_error( fatal, 'MPP_GET_INFO: invalid unit number,file '//trim(mpp_file(unit)%name))
63
64 if (size(global_atts(:)).lt.mpp_file(unit)%natt) &
65 call mpp_error(fatal, 'MPP_GET_ATTS: atttype not dimensioned properly in calling routine, file '// &
66 trim(mpp_file(unit)%name))
67
68 natt = mpp_file(unit)%natt
69 global_atts = default_att
70
71 do i=1,natt
72 global_atts(i) = mpp_file(unit)%Att(i)
73 enddo
74
75 return
76 end subroutine mpp_get_global_atts
77
78 !#####################################################################
79 subroutine mpp_get_field_atts(field, name, units, longname, min, max, missing, ndim, siz, axes, atts, &
80 valid, scale, add, checksum)
81
82 type(fieldtype), intent(in) :: field
83 character(len=*), intent(out), optional :: name, units
84 character(len=*), intent(out), optional :: longname
85 real, intent(out), optional :: min,max,missing
86 integer, intent(out), optional :: ndim
87 integer, intent(out), dimension(:), optional :: siz
88 type(validtype), intent(out), optional :: valid
89 real, intent(out), optional :: scale
90 real, intent(out), optional :: add
91 integer(i8_kind), intent(out), dimension(:), optional :: checksum
92
93 type(atttype), intent(inout), dimension(:), optional :: atts
94 type(axistype), intent(inout), dimension(:), optional :: axes
95
96 integer :: n,m, check_exist
97
98 if (PRESENT(name)) name = field%name
99 if (PRESENT(units)) units = field%units
100 if (PRESENT(longname)) longname = field%longname
101 if (PRESENT(min)) min = field%min
102 if (PRESENT(max)) max = field%max
103 if (PRESENT(missing)) missing = field%missing
104 if (PRESENT(ndim)) ndim = field%ndim
105 if (PRESENT(atts)) then
106 atts = default_att
107 n = size(atts(:));m=size(field%Att(:))
108 if (n.LT.m)&
109 call mpp_error(fatal,'attribute array not large enough in mpp_get_field_atts, field '//&
110 trim(field%name))
111 do n=1,m
112 atts(n) = field%Att(n)
113 end do
114 end if
115 if (PRESENT(axes)) then
116 axes = default_axis
117 n = size(axes(:));m=field%ndim
118 if (n.LT.m) &
119 call mpp_error(fatal,'axis array not large enough in mpp_get_field_atts, field '//&
120 trim(field%name))
121 do n=1,m
122 axes(n) = field%axes(n)
123 end do
124 end if
125 if (PRESENT(siz)) then
126 siz = -1
127 n = size(siz(:));m=field%ndim
128 if (n.LT.m) &
129 call mpp_error(fatal,'size array not large enough in mpp_get_field_atts, field '//&
130 trim(field%name))
131 do n=1,m
132 siz(n) = field%size(n)
133 end do
134 end if
135
136 if(PRESENT(valid)) then
137 call mpp_get_valid(field,valid)
138 endif
139
140 if(PRESENT(scale)) scale = field%scale
141 if(present(add)) add = field%add
142 if(present(checksum)) then
143 checksum = 0
144 check_exist = mpp_find_att(field%Att(:),"checksum")
145 if ( check_exist >= 0 ) then
146 if(size(checksum(:)) >size(field%checksum(:))) call mpp_error(fatal, &
147 & "size(checksum(:)) >size(field%checksum(:))")
148 checksum = field%checksum(1:size(checksum(:)))
149 endif
150 endif
151
152 return
153 end subroutine mpp_get_field_atts
154
155 !#####################################################################
156 subroutine mpp_get_axis_atts( axis, name, units, longname, cartesian, &
157 calendar, sense, len, natts, atts, compressed )
158
159 type(axistype), intent(in) :: axis
160 character(len=*), intent(out) , optional :: name, units
161 character(len=*), intent(out), optional :: longname, cartesian
162 character(len=*), intent(out), optional :: compressed, calendar
163 integer,intent(out), optional :: sense, len , natts
164 type(atttype), intent(inout), optional, dimension(:) :: atts
165
166 integer :: n,m
167
168 if (PRESENT(name)) name = axis%name
169 if (PRESENT(units)) units = axis%units
170 if (PRESENT(longname)) longname = axis%longname
171 if (PRESENT(cartesian)) cartesian = axis%cartesian
172 if (PRESENT(compressed)) compressed = axis%compressed
173 if (PRESENT(calendar)) calendar = axis%calendar
174 if (PRESENT(sense)) sense = axis%sense
175 if (PRESENT(len)) len = axis%len
176 if (PRESENT(atts)) then
177 atts = default_att
178 n = size(atts(:));m=size(axis%Att(:))
179 if (n.LT.m) &
180 call mpp_error(fatal,'attribute array not large enough in mpp_get_field_atts, axis '//&
181 trim(axis%name))
182 do n=1,m
183 atts(n) = axis%Att(n)
184 end do
185 end if
186 if (PRESENT(natts)) natts = size(axis%Att(:))
187
188 return
189 end subroutine mpp_get_axis_atts
190
191
192 !#####################################################################
193 !> @brief Copy variable information from file (excluding data)
194 subroutine mpp_get_fields( unit, variables )
195 integer, intent(in) :: unit
196 type(fieldtype), intent(inout) :: variables(:)
197
198 integer :: nvar,i
199
200 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_FIELDS: must first call mpp_io_init.' )
201 if( .NOT.mpp_file(unit)%opened )call mpp_error( fatal, 'MPP_GET_FIELDS: invalid unit number.' )
202
203 if (size(variables(:)).ne.mpp_file(unit)%nvar) &
204 call mpp_error(fatal,'MPP_GET_FIELDS: fieldtype not dimensioned properly in calling routine, file '//&
205 trim(mpp_file(unit)%name))
206
207 nvar = mpp_file(unit)%nvar
208
209 do i=1,nvar
210 variables(i) = mpp_file(unit)%Var(i)
211 enddo
212
213 return
214 end subroutine mpp_get_fields
215
216
217
218 !#####################################################################
219 !> @brief Copy variable information from file (excluding data)
220 subroutine mpp_get_axes( unit, axes, time_axis )
221 integer, intent(in) :: unit
222 type(axistype), intent(inout) :: axes(:)
223 type(axistype), intent(inout), optional :: time_axis
224 integer :: ndim,i
225
226 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_AXES: must first call mpp_io_init.' )
227 if( .NOT.mpp_file(unit)%opened )&
228 call mpp_error( fatal, 'MPP_GET_AXES: invalid unit number, file '//trim(mpp_file(unit)%name))
229
230 if (size(axes(:)).ne.mpp_file(unit)%ndim) &
231 call mpp_error(fatal, 'MPP_GET_AXES: axistype not dimensioned properly in calling routine, file '//&
232 trim(mpp_file(unit)%name))
233
234
235 if (PRESENT(time_axis)) time_axis = default_axis
236 ndim = mpp_file(unit)%ndim
237
238 do i=1,ndim
239 axes(i)=mpp_file(unit)%Axis(i)
240
241 if (PRESENT(time_axis) &
242 .AND. .NOT. ASSOCIATED(mpp_file(unit)%Axis(i)%data) &
243 .AND. mpp_file(unit)%Axis(i)%type /= -1) then
244 time_axis = mpp_file(unit)%Axis(i)
245 endif
246 enddo
247
248 return
249 end subroutine mpp_get_axes
250
251 !#####################################################################
252 !> @brief Copy variable information from file (excluding data)
253 function mpp_get_dimension_length(unit, dimname, found)
254 integer, intent(in) :: unit
255 character(len=*), intent(in) :: dimname
256 logical, optional, intent(out) :: found
257 integer :: mpp_get_dimension_length
258 logical :: found_dim
259 integer :: i
260
261
262 if( .NOT.module_is_initialized ) &
263 call mpp_error( fatal, 'mpp_get_dimension_length: must first call mpp_io_init.' )
264 if( .NOT.mpp_file(unit)%opened )&
265 call mpp_error( fatal, 'mpp_get_dimension_length: invalid unit number, file '//trim(mpp_file(unit)%name))
266 found_dim = .false.
268 do i = 1, mpp_file(unit)%ndim
269 if(trim(dimname) == trim(mpp_file(unit)%Axis(i)%name)) then
270 mpp_get_dimension_length = mpp_file(unit)%Axis(i)%len
271 found_dim = .true.
272 exit
273 endif
274 enddo
275
276 if(present(found)) found = found_dim
277
278 end function mpp_get_dimension_length
279
280 !#####################################################################
281 !> @brief Copy variable information from file (excluding data)
282 subroutine mpp_get_time_axis( unit, time_axis )
283 integer, intent(in) :: unit
284 type(axistype), intent(inout) :: time_axis
285
286 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_AXES: must first call mpp_io_init.' )
287 if( .NOT.mpp_file(unit)%opened )&
288 call mpp_error( fatal, 'MPP_GET_AXES: invalid unit number, file '//trim(mpp_file(unit)%name))
289
290 time_axis = mpp_file(unit)%Axis(mpp_file(unit)%recdimid)
291
292 return
293 end subroutine mpp_get_time_axis
294
295 !####################################################################
296 !> @brief Copy variable information from file (excluding data)
298 character(len=len(default_axis%calendar)) :: mpp_get_default_calendar
299
300 mpp_get_default_calendar = default_axis%calendar
301
302 end function mpp_get_default_calendar
303
304 !> @brief Get file time data.
305 !!
306 !> Copy time information from file and convert to time_type
307 !! <br>Example usage:
308 !! @code{.F90}
309 !! call mpp_get_times( unit, time_values)
310 !! @endcode
311 subroutine mpp_get_times( unit, time_values )
312 integer, intent(in) :: unit
313 real, intent(inout) :: time_values(:)
314
315 integer :: ntime,i
316
317 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_TIMES: must first call mpp_io_init.' )
318 if( .NOT.mpp_file(unit)%opened )&
319 call mpp_error(fatal, 'MPP_GET_TIMES: invalid unit number, file '//trim(mpp_file(unit)%name))
320
321! NF_INQ_DIM returns -1 for the length of a record dimension if
322! it does not exist
323
324 if (mpp_file(unit)%time_level == -1) then
325 time_values = 0.0
326 return
327 endif
328
329 if (size(time_values(:)).ne.mpp_file(unit)%time_level) &
330 call mpp_error(fatal,'MPP_GET_TIMES: time_values not dimensioned properly in calling routine, file '//&
331 trim(mpp_file(unit)%name))
332
333 ntime = mpp_file(unit)%time_level
334
335 do i=1,ntime
336 time_values(i) = mpp_file(unit)%time_values(i)
337 enddo
338
339 return
340 end subroutine mpp_get_times
341
342 !#####################################################################
343 function mpp_get_field_index(fields,fieldname)
344
345 type(fieldtype), dimension(:) :: fields
346 character(len=*) :: fieldname
347 integer :: mpp_get_field_index
348
349 integer :: n
350
351 mpp_get_field_index = -1
352
353 do n=1,size(fields(:))
354 if (lowercase(fields(n)%name) == lowercase(fieldname)) then
355 mpp_get_field_index = n
356 exit
357 endif
358 enddo
359
360 return
361 end function mpp_get_field_index
362
363 !#####################################################################
364 function mpp_get_axis_index(axes,axisname)
365
366 type(axistype), dimension(:) :: axes
367 character(len=*) :: axisname
368 integer :: mpp_get_axis_index
369
370 integer :: n
371
372 mpp_get_axis_index = -1
373
374 do n=1,size(axes(:))
375 if (lowercase(axes(n)%name) == lowercase(axisname)) then
376 mpp_get_axis_index = n
377 exit
378 endif
379 enddo
380
381 return
382 end function mpp_get_axis_index
383
384 !#####################################################################
385 function mpp_get_axis_by_name(unit,axisname)
386
387 integer :: unit
388 character(len=*) :: axisname
389 type(axistype) :: mpp_get_axis_by_name
390
391 integer :: n
392
393 mpp_get_axis_by_name = default_axis
394
395 do n=1,size(mpp_file(unit)%Axis(:))
396 if (lowercase(mpp_file(unit)%Axis(n)%name) == lowercase(axisname)) then
397 mpp_get_axis_by_name = mpp_file(unit)%Axis(n)
398 exit
399 endif
400 enddo
401
402 return
403 end function mpp_get_axis_by_name
404
405 !#####################################################################
406 function mpp_get_field_size(field)
407
408 type(fieldtype) :: field
409 integer :: mpp_get_field_size(4)
410
411 mpp_get_field_size = -1
412
413 mpp_get_field_size(1) = field%size(1)
414 mpp_get_field_size(2) = field%size(2)
415 mpp_get_field_size(3) = field%size(3)
416 mpp_get_field_size(4) = field%size(4)
417
418 return
419 end function mpp_get_field_size
420
421
422 !#####################################################################
423 function mpp_get_axis_length(axis)
424
425 type(axistype) :: axis
426 integer :: mpp_get_axis_length
427
428 mpp_get_axis_length = axis%len
429
430 return
431 end function mpp_get_axis_length
432
433 !#####################################################################
434 function mpp_get_axis_bounds(axis, data, name)
435 type(axistype), intent(in) :: axis
436 real, dimension(:), intent(out) :: data
437 character(len=*), optional, intent(out) :: name
438 logical :: mpp_get_axis_bounds
439
440 if (size(data(:)).lt.axis%len+1)&
441 call mpp_error(fatal,'MPP_GET_AXIS_BOUNDS: data array not large enough, axis '//trim(axis%name))
442 if (.NOT.ASSOCIATED(axis%data_bounds)) then
443 mpp_get_axis_bounds = .false.
444 else
445 mpp_get_axis_bounds = .true.
446 data(1:axis%len+1) = axis%data_bounds(:)
447 endif
448 if(present(name)) name = trim(axis%name_bounds)
449
450 return
451 end function mpp_get_axis_bounds
452
453 !#####################################################################
454 subroutine mpp_get_axis_data( axis, data )
455
456 type(axistype), intent(in) :: axis
457 real, dimension(:), intent(out) :: data
458
459
460 if (size(data(:)).lt.axis%len)&
461 call mpp_error(fatal,'MPP_GET_AXIS_DATA: data array not large enough, axis '//trim(axis%name))
462 if (.NOT.ASSOCIATED(axis%data)) then
463 call mpp_error(note,'MPP_GET_AXIS_DATA: use mpp_get_times for record dims')
464 data = 0.
465 else
466 data(1:axis%len) = axis%data
467 endif
468
469 return
470 end subroutine mpp_get_axis_data
471
472
473 !#####################################################################
474 function mpp_get_recdimid(unit)
475!
476 integer, intent(in) :: unit
477 integer :: mpp_get_recdimid
478
479
480 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GET_RECDIMID: must first call mpp_io_init.' )
481 if( .NOT.mpp_file(unit)%opened )call mpp_error( fatal, 'MPP_GET_RECDIMID: invalid unit number.' )
482
483 mpp_get_recdimid = mpp_file(unit)%recdimid
484
485 return
486 end function mpp_get_recdimid
487
488 !#####################################################################
489! <FUNCTION NAME="mpp_get_ncid">
490! <OVERVIEW>
491! Get netCDF ID of an open file.
492! </OVERVIEW>
493! <DESCRIPTION>
494! This returns the <TT>ncid</TT> associated with the open file on
495! <TT>unit</TT>. It is used in the instance that the user desires to
496! perform netCDF calls upon the file that are not provided by the
497! <TT>mpp_io_mod</TT> API itself.
498! </DESCRIPTION>
499! <TEMPLATE>
500! mpp_get_ncid(unit)
501! </TEMPLATE>
502! <IN NAME="unit" TYPE="integer"> </IN>
503! </FUNCTION>
504
505 !> @brief Get netCDF ID of an open file.
506 !!
507 !> This returns the <TT>ncid</TT> associated with the open file on
508 !! <TT>unit</TT>. It is used in the instance that the user desires to
509 !! perform netCDF calls upon the file that are not provided by the
510 !! <TT>mpp_io_mod</TT> API itself.
511 function mpp_get_ncid(unit)
512 integer :: mpp_get_ncid
513 integer, intent(in) :: unit
514
515 mpp_get_ncid = mpp_file(unit)%ncid
516 return
517 end function mpp_get_ncid
518
519 !#####################################################################
520 function mpp_get_axis_id(axis)
521 integer mpp_get_axis_id
522 type(axistype), intent(in) :: axis
523 mpp_get_axis_id = axis%id
524 return
525 end function mpp_get_axis_id
526
527 !#####################################################################
528 function mpp_get_field_id(field)
529 integer mpp_get_field_id
530 type(fieldtype), intent(in) :: field
531 mpp_get_field_id = field%id
532 return
533 end function mpp_get_field_id
534
535 !#####################################################################
536 !> @brief Set the mpp_io_stack variable to be at least n LONG words long
538 integer, intent(in) :: n
539 character(len=10) :: text
540
541 if( n.GT.mpp_io_stack_size .AND. allocated(mpp_io_stack) )deallocate(mpp_io_stack)
542 if( .NOT.allocated(mpp_io_stack) )then
543 allocate( mpp_io_stack(n) )
544 mpp_io_stack_size = n
545 write( text,'(i10)' )n
546 if( pe.EQ.mpp_root_pe() )call mpp_error( note, 'MPP_IO_SET_STACK_SIZE: stack size set to '//text//'.' )
547 end if
548
549 return
550 end subroutine mpp_io_set_stack_size
551
552 !#####################################################################
553 !> Based on presence/absence of attributes, defines valid range or missing
554 ! value. For details, see section 8.1 of NetCDF User Guide
555 subroutine mpp_get_valid(f,v)
556 type(fieldtype),intent(in) :: f ! field
557 type(validtype),intent(out) :: v ! validator
558
559 integer :: irange,imin,imax,ifill,imissing,iscale
560 integer :: valid_T, scale_T ! types of attributes
561
562 v%is_range = .true.
563 v%min = -huge(v%min); v%max = huge(v%max)
564 if (f%natt == 0) return
565 ! find indices of relevant attributes
566 irange = mpp_find_att(f%att,'valid_range')
567 imin = mpp_find_att(f%att,'valid_min')
568 imax = mpp_find_att(f%att,'valid_max')
569 ifill = mpp_find_att(f%att,'_FillValue')
570 imissing = mpp_find_att(f%att,'missing_value')
571
572 ! find the widest type of scale and offset; note that the code
573 ! uses assumption that NetCDF types are arranged in th order of rank,
574 ! that is NF_BYTE < NF_SHORT < NF_INT < NF_FLOAT < NF_DOUBLE
575 scale_t = 0
576 iscale = mpp_find_att(f%att,'scale_factor')
577 if(iscale>0) scale_t = f%att(iscale)%type
578 iscale = mpp_find_att(f%att,'add_offset')
579 if(iscale>0) scale_t = max(scale_t,f%att(iscale)%type)
580
581
582 ! examine possible range attributes
583 valid_t = 0
584 if (irange>0) then
585 v%min = f%att(irange)%fatt(1)
586 v%max = f%att(irange)%fatt(2)
587 valid_t = f%att(irange)%type
588 else if (imax>0.or.imin>0) then
589 if(imax>0) then
590 v%max = f%att(imax)%fatt(1)
591 valid_t = max(valid_t,f%att(imax)%type)
592 endif
593 if(imin>0) then
594 v%min = f%att(imin)%fatt(1)
595 valid_t = max(valid_t,f%att(imin)%type)
596 endif
597 else if (imissing > 0) then
598 v%is_range = .false.
599 ! here we always scale, since missing_value is supposed to be in
600 ! external representation
601 v%min = f%att(imissing)%fatt(1)*f%scale + f%add
602 else if (ifill>0) then
603 !z1l ifdef is added in to be able to compile without using use_netCDF.
604#ifdef use_netCDF
605 ! define min and max according to _FillValue
606 if(f%att(ifill)%fatt(1)>0) then
607 ! if _FillValue is positive, then it defines valid maximum
608 v%max = f%att(ifill)%fatt(1)
609 select case(f%type)
610 case (nf_byte,nf_short,nf_int)
611 v%max = v%max-1
612 case (nf_float)
613 v%max = nearest(nearest(real(v%max,4),-1.0),-1.0)
614 case (nf_double)
615 v%max = nearest(nearest(real(v%max,8),-1.0),-1.0)
616 end select
617 ! always do the scaling, as the _FillValue is in external
618 ! representation
619 v%max = v%max*f%scale + f%add
620 else
621 ! if _FillValue is negative or zero, then it defines valid minimum
622 v%min = f%att(ifill)%fatt(1)
623 select case(f%type)
624 case (nf_byte,nf_short,nf_int)
625 v%min = v%min+1
626 case (nf_float)
627 v%min = nearest(nearest(real(v%min,4),+1.0),+1.0)
628 case (nf_double)
629 v%min = nearest(nearest(real(v%min,8),+1.0),+1.0)
630 end select
631 ! always do the scaling, as the _FillValue is in external
632 ! representation
633 v%min = v%min*f%scale + f%add
634 endif
635#endif
636 endif
637 ! If valid_range is the same type as scale_factor (actually the wider of
638 ! scale_factor and add_offset) and this is wider than the external data, then it
639 ! will be interpreted as being in the units of the internal (unpacked) data.
640 ! Otherwise it is in the units of the external (packed) data.
641 ! Note that it is not relevant if we went through the missing_data of _FillValue
642 ! brances, because in this case all irange, imin, and imax are less then 0
643 if(.not.((valid_t == scale_t).and.(scale_t>f%type))) then
644 if(irange>0 .or. imin>0) then
645 v%min = v%min*f%scale + f%add
646 endif
647 if(irange>0 .or. imax>0) then
648 v%max = v%max*f%scale + f%add
649 endif
650 endif
651
652 end subroutine mpp_get_valid
653
654 !#####################################################################
655 logical elemental function mpp_is_valid(x, v)
656 real , intent(in) :: x ! real value to be eaxmined
657 type(validtype), intent(in) :: v ! validator
658
659 if (v%is_range) then
660 mpp_is_valid = (v%min<=x).and.(x<=v%max)
661 else
662 mpp_is_valid = x/=v%min
663 endif
664 end function mpp_is_valid
665
666 !#####################################################################
667 ! finds an attribute by name in the array; returns -1 if it is not
668 ! found
669 function mpp_find_att(atts, name)
670 integer :: mpp_find_att
671 type(atttype), intent(in) :: atts(:) ! array of attributes
672 character(len=*) :: name ! name of the attributes
673
674 integer :: i
675
676 mpp_find_att = -1
677 do i = 1, size(atts)
678 if (trim(name)==trim(atts(i)%name)) then
679 mpp_find_att=i
680 exit
681 endif
682 enddo
683 end function mpp_find_att
684 !#####################################################################
685
686 !> @brief return the name of an attribute.
687 function mpp_get_att_name(att)
688 type(atttype), intent(in) :: att
689 character(len=len(att%name)) :: mpp_get_att_name
690
691 mpp_get_att_name = att%name
692 return
693
694 end function mpp_get_att_name
695
696 !#####################################################################
697
698 !> @brief return the type of an attribute.
699 function mpp_get_att_type(att)
700 type(atttype), intent(in) :: att
701 integer :: mpp_get_att_type
702
703 mpp_get_att_type = att%type
704 return
705
706 end function mpp_get_att_type
707
708 !#####################################################################
709
710 !> @brief return the length of an attribute.
711 function mpp_get_att_length(att)
712 type(atttype), intent(in) :: att
713 integer :: mpp_get_att_length
714
715 mpp_get_att_length = att%len
716
717 return
718
719 end function mpp_get_att_length
720
721 !#####################################################################
722
723 !> @brief return the char value of an attribute.
724 function mpp_get_att_char(att)
725 type(atttype), intent(in) :: att
726 character(len=att%len) :: mpp_get_att_char
727
728 mpp_get_att_char = att%catt
729 return
730
731 end function mpp_get_att_char
732
733 !#####################################################################
734
735 !> @brief return the real array value of an attribute.
736 function mpp_get_att_real(att)
737 type(atttype), intent(in) :: att
738 real, dimension(size(att%fatt(:))) :: mpp_get_att_real
739
740 mpp_get_att_real = att%fatt
741 return
742
743 end function mpp_get_att_real
744
745 !#####################################################################
746
747 !> @brief return the real array value of an attribute.
749 type(atttype), intent(in) :: att
751
752 mpp_get_att_real_scalar = att%fatt(1)
753 return
754
755 end function mpp_get_att_real_scalar
756
757 !#####################################################################
758 !> @brief return the name of an field
759 function mpp_get_field_name(field)
760 type(fieldtype), intent(in) :: field
761 character(len=len(field%name)) :: mpp_get_field_name
762
763 mpp_get_field_name = field%name
764 return
765 end function mpp_get_field_name
766
767 !#####################################################################
768 !> @brief return the file name of corresponding unit
769 function mpp_get_file_name(unit)
770 integer, intent(in) :: unit
771 character(len=len(mpp_file(1)%name)) :: mpp_get_file_name
772
773 mpp_get_file_name = mpp_file(unit)%name
774 return
775
776 end function mpp_get_file_name
777
778 !####################################################################
779 !> @brief return if certain file with unit is opened or not
780 function mpp_file_is_opened(unit)
781 integer, intent(in) :: unit
782 logical :: mpp_file_is_opened
783
784 mpp_file_is_opened = mpp_file(unit)%opened
785 return
786
787 end function mpp_file_is_opened
788
789 !####################################################################
790 !> @brief return the attribute value of given field name
791 subroutine mpp_get_field_att_text(unit, fieldname, attname, attvalue)
792 integer, intent(in) :: unit
793 character(len=*), intent(in) :: fieldname, attname
794 character(len=*), intent(out) :: attvalue
795 logical :: found_field, found_att
796 integer :: i, j, length
797
798 found_field = .false.
799 found_att = .false.
800 do i=1,mpp_file(unit)%nvar
801 if( trim(mpp_file(unit)%Var(i)%name) == trim(fieldname)) then
802 found_field = .true.
803 do j=1, size(mpp_file(unit)%Var(i)%Att(:))
804 if( trim(mpp_file(unit)%Var(i)%Att(j)%name) == trim(attname) ) then
805 found_att = .true.
806 length = mpp_file(unit)%Var(i)%Att(j)%len
807 if(len(attvalue) .LE. length ) call mpp_error(fatal, &
808 'mpp_io_util.inc: length of attvalue is less than the length of catt')
809 attvalue = trim(mpp_file(unit)%Var(i)%Att(j)%catt(1:length))
810 exit
811 end if
812 end do
813 exit
814 end if
815 end do
816
817 if(.NOT. found_field) call mpp_error(fatal,"mpp_io_util.inc: field "//trim(fieldname)// &
818 " does not exist in the file "//trim(mpp_file(unit)%name) )
819 if(.NOT. found_att) call mpp_error(fatal,"mpp_io_util.inc: attribute "//trim(attname)//" of field "&
820 //trim(fieldname)// " does not exist in the file "//trim(mpp_file(unit)%name) )
821
822 return
823
824 end subroutine mpp_get_field_att_text
825
826
827 !####################################################################
828 !> @brief return mpp_io_nml variable io_clock_on
830 logical :: mpp_io_clock_on
831
832 mpp_io_clock_on = io_clocks_on
833 return
834
835 end function mpp_io_clock_on
836
837
838 function mpp_attribute_exist(field,name)
839 logical :: mpp_attribute_exist
840 type(fieldtype), intent(in) :: field ! The field that you are searching for the attribute.
841 character(len=*), intent(in) :: name ! name of the attributes
842
843 if(field%natt > 0) then
844 mpp_attribute_exist = ( mpp_find_att(field%Att(:),name) > 0 )
845 else
846 mpp_attribute_exist = .false.
847 endif
848
849 end function mpp_attribute_exist
850
851!#######################################################################
852subroutine mpp_dist_io_pelist(ssize,pelist)
853 integer, intent(in) :: ssize ! Stripe size for dist read
854 integer, allocatable, intent(out) :: pelist(:)
855 integer :: i, lsize, ioroot
856 logical :: is_ioroot=.false.
857
858 ! Did you make a mistake?
859 if(ssize < 1) call mpp_error(fatal,'mpp_dist_io_pelist: I/O stripe size < 1')
860
861 is_ioroot = mpp_is_dist_ioroot(ssize,ioroot=ioroot,lsize=lsize)
862
863 ! Did I make a mistake?
864 if(lsize < 1) call mpp_error(fatal,'mpp_dist_io_pelist: size of pelist < 1')
865
866 allocate(pelist(lsize))
867 do i=1,lsize
868 pelist(i) = ioroot + i - 1
869 enddo
870end subroutine mpp_dist_io_pelist
871
872!#######################################################################
873logical function mpp_is_dist_ioroot(ssize,ioroot,lsize)
874 integer, intent(in) :: ssize ! Dist io set size
875 integer, intent(out), optional :: ioroot, lsize
876 integer :: pe, npes, mypos, maxpe, d_ioroot, d_lsize, last_ioroot
877 integer :: rootpe
878
879 if(ssize < 1) call mpp_error(fatal,'mpp_is_dist_ioroot: I/O stripe size < 1')
880
881 mpp_is_dist_ioroot = .false.
882 rootpe = mpp_root_pe()
883 d_lsize = ssize
884 pe = mpp_pe()
885 mypos = modulo(pe-rootpe,ssize) ! Which PE am I in the io group?
886 d_ioroot = pe - mypos ! What is the io root for the group?
887 npes = mpp_npes()
888 maxpe = min(d_ioroot+ssize,npes+rootpe) - 1 ! Handle end case
889 d_lsize = maxpe - d_ioroot + 1
890 if(mod(npes,ssize) == 1)then ! Ensure there are no sets with 1 member
891 last_ioroot = (npes-1) - ssize
892 if(pe >= last_ioroot) then
893 d_ioroot = last_ioroot
894 d_lsize = ssize + 1
895 endif
896 endif
897 if(pe == d_ioroot) mpp_is_dist_ioroot = .true.
898 if(PRESENT(ioroot)) ioroot = d_ioroot
899 if(PRESENT(lsize)) lsize = d_lsize
900end function mpp_is_dist_ioroot
901!> @}
character(len=len(mpp_file(1)%name)) function mpp_get_file_name(unit)
return the file name of corresponding unit
subroutine mpp_get_info(unit, ndim, nvar, natt, ntime)
Get some general information about a file.
subroutine mpp_get_global_atts(unit, global_atts)
Copy global file attributes for use by user.
subroutine mpp_io_set_stack_size(n)
Set the mpp_io_stack variable to be at least n LONG words long.
integer function mpp_get_ncid(unit)
Get netCDF ID of an open file.
integer function mpp_get_dimension_length(unit, dimname, found)
Copy variable information from file (excluding data)
subroutine mpp_get_times(unit, time_values)
Get file time data.
character(len=len(default_axis%calendar)) function mpp_get_default_calendar()
Copy variable information from file (excluding data)
real function mpp_get_att_real_scalar(att)
return the real array value of an attribute.
logical function mpp_file_is_opened(unit)
return if certain file with unit is opened or not
subroutine mpp_get_valid(f, v)
Based on presence/absence of attributes, defines valid range or missing.
subroutine mpp_get_fields(unit, variables)
Copy variable information from file (excluding data)
subroutine mpp_get_field_att_text(unit, fieldname, attname, attvalue)
return the attribute value of given field name
character(len=len(field%name)) function mpp_get_field_name(field)
return the name of an field
subroutine mpp_get_time_axis(unit, time_axis)
Copy variable information from file (excluding data)
integer function mpp_get_att_length(att)
return the length of an attribute.
subroutine mpp_get_axes(unit, axes, time_axis)
Copy variable information from file (excluding data)
character(len=len(att%name)) function mpp_get_att_name(att)
return the name of an attribute.
real function, dimension(size(att%fatt(:))) mpp_get_att_real(att)
return the real array value of an attribute.
logical function mpp_io_clock_on()
return mpp_io_nml variable io_clock_on
integer function mpp_get_att_type(att)
return the type of an attribute.
character(len=att%len) function mpp_get_att_char(att)
return the char value of an attribute.