48 mpp_get_att_name, mpp_get_att_type, mpp_get_att_char, &
49 mpp_get_att_length, mpp_get_axis_bounds
55 # include <netcdf.inc> 63 real,
parameter ::
epsln= 1.e-10
64 real,
parameter ::
fp5 = 0.5,
f360 = 360.0
67 #include<file_version.h> 81 character(len=1),
intent(out) :: cart
82 character(len=1) :: axis_cart
83 character(len=16),
dimension(2) :: lon_names, lat_names
84 character(len=16),
dimension(3) :: z_names
85 character(len=16),
dimension(2) :: t_names
86 character(len=16),
dimension(3) :: lon_units, lat_units
87 character(len=8) ,
dimension(4) :: z_units
88 character(len=3) ,
dimension(6) :: t_units
89 character(len=32) :: name
92 lon_names = (/
'lon',
'x '/)
93 lat_names = (/
'lat',
'y '/)
94 z_names = (/
'depth ',
'height',
'z '/)
95 t_names = (/
'time',
't '/)
96 lon_units = (/
'degrees_e ',
'degrees_east',
'degreese '/)
97 lat_units = (/
'degrees_n ',
'degrees_north',
'degreesn '/)
98 z_units = (/
'cm ',
'm ',
'pa ',
'hpa'/)
99 t_units = (/
'sec',
'min',
'hou',
'day',
'mon',
'yea'/)
104 if ( lowercase(axis_cart) ==
'x' ) cart =
'X' 105 if ( lowercase(axis_cart) ==
'y' ) cart =
'Y' 106 if ( lowercase(axis_cart) ==
'z' ) cart =
'Z' 107 if ( lowercase(axis_cart) ==
't' ) cart =
'T' 109 if (cart /=
'X' .and. cart /=
'Y' .and. cart /=
'Z' .and. cart /=
'T')
then 111 name = lowercase(name)
112 do i=1,
size(lon_names(:))
113 if (trim(name(1:3)) == trim(lon_names(i))) cart =
'X' 115 do i=1,
size(lat_names(:))
116 if (trim(name(1:3)) == trim(lat_names(i))) cart =
'Y' 118 do i=1,
size(z_names(:))
119 if (trim(name) == trim(z_names(i))) cart =
'Z' 121 do i=1,
size(t_names(:))
122 if (trim(name) == t_names(i)) cart =
'T' 126 if (cart /=
'X' .and. cart /=
'Y' .and. cart /=
'Z' .and. cart /=
'T')
then 128 name = lowercase(name)
129 do i=1,
size(lon_units(:))
130 if (trim(name) == trim(lon_units(i))) cart =
'X' 132 do i=1,
size(lat_units(:))
133 if (trim(name) == trim(lat_units(i))) cart =
'Y' 135 do i=1,
size(z_units(:))
136 if (trim(name) == trim(z_units(i))) cart =
'Z' 138 do i=1,
size(t_units(:))
139 if (name(1:3) == trim(t_units(i))) cart =
'T' 151 type(
axistype),
intent(inout) :: axis_bound
152 type(
axistype),
intent(in),
dimension(:) :: axes
153 character(len=*),
intent(inout),
optional :: bnd_name
154 character(len=*),
intent(out),
optional :: err_msg
156 real,
dimension(:),
allocatable :: data, tmp
159 character(len=128) :: name, units
160 character(len=256) :: longname
161 character(len=1) :: cartesian
162 logical :: bounds_found
164 if(
present(err_msg))
then 169 cartesian=cartesian, len=len)
170 if(len .LE. 0)
return 171 allocate(
data(len+1))
173 bounds_found = mpp_get_axis_bounds(axis,
data, name=name)
174 longname = trim(longname)//
' bounds' 176 if(.not.bounds_found .and. len>1 )
then 179 name = trim(name)//
'_bnds' 181 call mpp_get_axis_data(axis,tmp)
183 data(i)= tmp(i-1)+
fp5*(tmp(i)-tmp(i-1))
185 data(1)= tmp(1)-
fp5*(tmp(2)-tmp(1))
186 if (abs(
data(1)) <
epsln)
data(1) = 0.0
187 data(len+1)= tmp(len)+
fp5*(tmp(len)-tmp(len-1))
188 if (
data(1) == 0.0)
then 189 if (abs(
data(len+1)-360.) >
epsln)
data(len+1)=360.0
192 if(bounds_found .OR. len>1)
then 194 longname,cartesian=cartesian,data=data)
196 if(
allocated(tmp))
deallocate(tmp)
207 type(
atttype),
dimension(:),
allocatable :: atts
216 if (lowercase(trim(mpp_get_att_name(atts(i)))) ==
'modulo')
get_axis_modulo = .true.
228 character(len=*),
intent(out) :: tbeg, tend
230 type(
atttype),
dimension(:),
allocatable :: atts
231 logical :: found_tbeg, found_tend
241 if(lowercase(trim(mpp_get_att_name(atts(i)))) ==
'modulo_beg')
then 242 if(mpp_get_att_length(atts(i)) > len(tbeg))
then 243 call mpp_error(fatal,
'error in get: len(tbeg) too small to hold attribute')
245 tbeg = trim(mpp_get_att_char(atts(i)))
248 if(lowercase(trim(mpp_get_att_name(atts(i)))) ==
'modulo_end')
then 249 if(mpp_get_att_length(atts(i)) > len(tend))
then 250 call mpp_error(fatal,
'error in get: len(tend) too small to hold attribute')
252 tend = trim(mpp_get_att_char(atts(i)))
257 if(found_tbeg .and. .not.found_tend)
then 258 call mpp_error(fatal,
'error in get: Found modulo_beg but not modulo_end')
260 if(.not.found_tbeg .and. found_tend)
then 261 call mpp_error(fatal,
'error in get: Found modulo_end but not modulo_beg')
273 type(
atttype),
dimension(:),
allocatable :: atts
282 if (mpp_get_att_char(atts(i)) ==
'fold_top')
get_axis_fold = .true.
318 subroutine tranlon(lon, lon_start, istrt)
327 real,
intent(inout),
dimension(:) :: lon
328 real,
intent(in) :: lon_start
329 integer,
intent(out) :: istrt
333 real :: lon_strt, tmp(
size(lon(:))-1)
343 if (lon(i+1) < lon(i))
then 350 if (abs(lon(len)-lon(1)) <
epsln)
then 351 tmp = cshift(lon(1:len-1),istrt-1)
355 lon = cshift(lon,istrt-1)
405 integer :: ia, i, ii, unit
407 real,
dimension(:) :: array
413 if (array(i) < array(i-1))
then 415 write (unit,*)
'=> Error: "frac_index" array must be monotonically increasing when searching for nearest value to ',&
417 write (unit,*)
' array(i) < array(i-1) for i=',i
418 write (unit,*)
' array(i) for i=1..ia follows:' 420 write (unit,*)
'i=',ii,
' array(i)=',array(ii)
422 call mpp_error(fatal,
' "frac_index" array must be monotonically increasing.')
425 if (
value < array(1) .or.
value > array(ia))
then 432 do while (i <= ia .and. keep_going)
434 if (
value <= array(i))
then 435 frac_index = float(i-1) + (
value-array(i-1))/(array(i)-array(i-1))
483 real,
dimension(:) :: array
489 if (array(i) < array(i-1))
then 491 write (unit,*)
'=> Error: "nearest_index" array must be monotonically increasing & 492 &when searching for nearest value to ',
value 493 write (unit,*)
' array(i) < array(i-1) for i=',i
494 write (unit,*)
' array(i) for i=1..ia follows:' 496 write (unit,*)
'i=',ii,
' array(i)=',array(ii)
498 call mpp_error(fatal,
' "nearest_index" array must be monotonically increasing.')
501 if (
value < array(1) .or.
value > array(ia))
then 507 do while (i <= ia .and. keep_going)
509 if (
value <= array(i))
then 522 real,
dimension(:),
intent(in) :: grid1, data1, grid2
523 real,
dimension(:),
intent(inout) :: data2
525 integer :: n1, n2, i, n, ext
533 if (grid1(i) <= grid1(i-1))
call mpp_error(fatal,
'grid1 not monotonic')
537 if (grid2(i) <= grid2(i-1))
call mpp_error(fatal,
'grid2 not monotonic')
540 if (grid1(1) > grid2(1) )
call mpp_error(fatal,
'grid2 lies outside grid1')
541 if (grid1(n1) < grid2(n2) )
call mpp_error(fatal,
'grid2 lies outside grid1')
546 if (grid1(n) < grid2(i))
then 547 w = (grid2(i)-grid1(n))/(grid1(n+1)-grid1(n))
548 data2(i) = (1.-w)*data1(n) + w*data1(n+1)
553 w = (grid2(i)-grid1(n-1))/(grid1(n)-grid1(n-1))
554 data2(i) = (1.-w)*data1(n-1) + w*data1(n)
567 real,
dimension(:),
intent(in) :: grid1, grid2, data1
568 real,
dimension(:),
intent(inout) :: data2
569 real,
intent(in) :: yp1, ypn
571 real,
dimension(size(grid1)) :: y2, u
572 real :: sig, p, qn, un, h, a ,b
573 integer :: n, m, i, k, klo, khi
579 if (grid1(i) <= grid1(i-1))
call mpp_error(fatal,
'grid1 not monotonic')
583 if (grid2(i) <= grid2(i-1))
call mpp_error(fatal,
'grid2 not monotonic')
586 if (grid1(1) > grid2(1) )
call mpp_error(fatal,
'grid2 lies outside grid1')
587 if (grid1(n) < grid2(m) )
call mpp_error(fatal,
'grid2 lies outside grid1')
589 if (yp1 >.99e30)
then 594 u(1)=(3./(grid1(2)-grid1(1)))*((data1(2)-data1(1))/(grid1(2)-grid1(1))-yp1)
598 sig=(grid1(i)-grid1(i-1))/(grid1(i+1)-grid1(i-1))
601 u(i)=(6.*((data1(i+1)-data1(i))/(grid1(i+1)-grid1(i))-(data1(i)-data1(i-1)) &
602 /(grid1(i)-grid1(i-1)))/(grid1(i+1)-grid1(i-1))-sig*u(i-1))/p
605 if (ypn > .99e30)
then 610 un=(3./(grid1(n)-grid1(n-1)))*(ypn-(data1(n)-data1(n-1))/(grid1(n)-grid1(n-1)))
613 y2(n)=(un-qn*u(n-1))/(qn*y2(n-1)+1.)
616 y2(k)=y2(k)*y2(k+1)+u(k)
621 if (grid1(n) < grid2(k))
then 631 h = grid1(khi)-grid1(klo)
632 a = (grid1(khi) - grid2(k))/h
633 b = (grid2(k) - grid1(klo))/h
634 data2(k) = a*data1(klo) + b*data1(khi)+ ((a**3-a)*y2(klo) + (b**3-b)*y2(khi))*(h**2)/6.
641 subroutine interp_1d_1d(grid1,grid2,data1,data2, method, yp1, yp2)
643 real,
dimension(:),
intent(in) :: grid1, data1, grid2
644 real,
dimension(:),
intent(inout) :: data2
645 character(len=*),
optional,
intent(in) :: method
646 real,
optional,
intent(in) :: yp1, yp2
649 character(len=32) :: interp_method
650 integer :: k2, ks, ke
654 interp_method =
"linear" 655 if(
present(method)) interp_method = method
657 if(
present(yp1)) y1 = yp1
659 if(
present(yp2)) y2 = yp2
660 call find_index(grid1, grid2(1), grid2(k2), ks, ke)
661 select case(trim(interp_method))
667 call mpp_error(fatal,
"axis_utils: interp_method should be linear or cubic_spline")
679 real,
dimension(:,:),
intent(in) :: grid1, data1, grid2
680 real,
dimension(:,:),
intent(inout) :: data2
682 integer :: n1, n2, i, n, k2, ks, ke
689 if (n1 /= n2)
call mpp_error(fatal,
'grid size mismatch')
692 call find_index(grid1(n,:), grid2(n,1), grid2(n,k2), ks, ke)
702 subroutine interp_1d_3d(grid1,grid2,data1,data2, method, yp1, yp2)
704 real,
dimension(:,:,:),
intent(in) :: grid1, data1, grid2
705 real,
dimension(:,:,:),
intent(inout) :: data2
706 character(len=*),
optional,
intent(in) :: method
707 real,
optional,
intent(in) :: yp1, yp2
709 integer :: n1, n2, m1, m2, k2, i, n, m
711 character(len=32) :: interp_method
719 interp_method =
"linear" 720 if(
present(method)) interp_method = method
722 if(
present(yp1)) y1 = yp1
724 if(
present(yp2)) y2 = yp2
726 if (n1 /= n2 .or. m1 /= m2)
call mpp_error(fatal,
'grid size mismatch')
728 select case(trim(interp_method))
732 call find_index(grid1(n,m,:), grid2(n,m,1), grid2(n,m,k2), ks, ke)
733 call interp_1d_linear(grid1(n,m,ks:ke),grid2(n,m,:),data1(n,m,ks:ke),data2(n,m,:))
739 call find_index(grid1(n,m,:), grid2(n,m,1), grid2(n,m,k2), ks, ke)
740 call interp_1d_cubic_spline(grid1(n,m,ks:ke),grid2(n,m,:), data1(n,m,ks:ke),data2(n,m,:), y1, y2)
744 call mpp_error(fatal,
"axis_utils: interp_method should be linear or cubic_spline")
754 real,
dimension(:),
intent(in) :: grid1
755 real,
intent(in) :: xs, xe
756 integer,
intent(out) :: ks, ke
764 if(grid1(k) <= xs .and. grid1(k+1) > xs )
then 770 if(grid1(k) >= xe .and. grid1(k-1) < xe )
then 776 if(ks == 0 )
call mpp_error(fatal,
' xs locate outside of grid1')
777 if(ke == 0 )
call mpp_error(fatal,
' xe locate outside of grid1')
783 #ifdef test_axis_utils 797 integer,
parameter :: maxsize = 100
801 real,
dimension(MAXSIZE) :: grid_src = 0
802 real,
dimension(MAXSIZE) :: grid_dst = 0
803 real,
dimension(MAXSIZE) :: data_src = 0
805 namelist / test_axis_utils_nml / n_src, n_dst, grid_src, grid_dst, data_src
807 real,
allocatable :: data_dst(:)
808 integer :: unit, ierr, io
815 grid_src(1:n_src) = (/ -63.6711465476916, -63.6711455476916, 166.564180735096, 401.25299580552, &
816 641.056493022762, 886.219516665347, 1137.35352761133, 1394.4936854079, &
817 1657.17893448689, 1925.64572676068, 2200.13183483549, 2480.9124139255, &
818 2768.35396680912, 3062.86513953019, 3675.47369643284, 4325.10564183322, &
819 5020.19039479527, 5769.85432323481, 6584.25101514851, 7475.94655633703, &
820 8462.01951335773, 9568.28246037887, 10178.3869413515, 10834.1425668942, &
821 11543.5265942777, 12317.3907407535, 13170.4562394288, 14125.6466646843, &
822 15225.8720618086, 16554.7859690842, 19697.1334102613 /)
823 grid_dst(1:n_dst) = (/ 1002.9522552602, 1077.51144617887, 1163.37842788755, 1264.19848463606, &
824 1382.57557953916, 1521.56713587855, 1684.76300370633, 1876.37817787584, &
825 2101.36166220498, 2365.52429149707, 2675.68881278444, 3039.86610206727, &
826 3467.4620678435, 3969.52058529847, 4553.81573511231, 5159.54844211827, &
827 5765.28114912423, 6371.01385613019, 6976.74656313614, 7582.4792701421, &
828 8188.21197714806, 8793.94468415402, 9399.67739115997, 10005.4100981659, &
829 10611.1428051719, 11216.8755121778, 11822.6082191838, 12428.3409261898, &
830 13034.0736331957, 13639.8063402017, 14245.5390472076, 14851.2717542136, &
831 15457.0044612196, 16062.7371682255, 16668.4698752315, 17274.2025822374, &
832 17879.9352892434, 18485.6679962493, 19091.4007032553, 19697.1334102613 /)
833 data_src(1:n_src) = (/ 309.895999643929, 309.991081541887, 309.971074746584, 310.873654697145, &
834 311.946530606618, 312.862249229647, 314.821236806913, 315.001269608758, &
835 315.092410930288, 315.19010999336, 315.122964496815, 315.057882573487, &
836 314.998796850493, 314.984586411292, 315.782246062002, 318.142544345795, &
837 321.553905292867, 325.247730854554, 329.151282227113, 332.835673638378, &
838 336.810414210932, 341.64530983048, 344.155248759994, 346.650476976385, &
839 349.106430095269, 351.915323032738, 354.709396583792, 359.68904432446, &
840 371.054289820675, 395.098187506342, 446.150726850039 /)
844 #ifdef INTERNAL_FILE_NML 846 ierr = check_nml_error(io,
'test_axis_utils_nml')
848 if(file_exist(
'input.nml'))
then 849 unit = open_namelist_file()
852 read (unit, nml=test_axis_utils_nml, iostat=io, end=10)
853 ierr = check_nml_error(io,
'test_axis_utils_nml')
855 10
call close_file(unit)
859 if(n_src >maxsize)
call mpp_error(fatal,
'test_axis_utils: nml n_src is greater than MAXSIZE')
860 if(n_dst >maxsize)
call mpp_error(fatal,
'test_axis_utils: nml n_dst is greater than MAXSIZE')
862 allocate(data_dst(n_dst) )
868 write(unit,*)
' the source grid is ', grid_src(1:n_src)
869 write(unit,*)
' the destination grid is ', grid_dst(1:n_dst)
870 write(unit,*)
' the source data is ', data_src(1:n_src)
871 call interp_1d(grid_src(1:n_src), grid_dst(1:n_dst), data_src(1:n_src), data_dst,
"linear")
872 write(unit,*)
' the destination data using linear interpolation is ', data_dst(1:n_dst)
873 call interp_1d(grid_src(1:n_src), grid_dst(1:n_dst), data_src(1:n_src), data_dst,
"cubic_spline")
874 write(unit,*)
' the destination data using cublic spline interpolation is ', data_dst(1:n_dst)
879 #endif /* test_axis_utils */
type(atttype), save, public default_att
integer, parameter maxatts
integer function, public nearest_index(value, array)
logical function, public get_axis_modulo(axis)
logical function, public fms_error_handler(routine, message, err_msg)
logical function, public get_axis_modulo_times(axis, tbeg, tend)
subroutine interp_1d_1d(grid1, grid2, data1, data2, method, yp1, yp2)
integer function, public check_nml_error(IOSTAT, NML_NAME)
subroutine interp_1d_3d(grid1, grid2, data1, data2, method, yp1, yp2)
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
subroutine, public fms_init(localcomm)
subroutine find_index(grid1, xs, xe, ks, ke)
subroutine interp_1d_cubic_spline(grid1, grid2, data1, data2, yp1, ypn)
subroutine, public get_axis_cart(axis, cart)
type(axistype), save, public default_axis
logical function, public get_axis_fold(axis)
subroutine interp_1d_linear(grid1, grid2, data1, data2)
subroutine interp_1d_2d(grid1, grid2, data1, data2)
************************************************************************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)
subroutine, public get_axis_bounds(axis, axis_bound, axes, bnd_name, err_msg)
real function, public frac_index(value, array)
logical function, public string_array_index(string, string_array, index)
real function, public lon_in_range(lon, l_strt)
subroutine, public tranlon(lon, lon_start, istrt)