FMS  2025.04
Flexible Modeling System
axis_utils2.F90
1 !***********************************************************************
2 !* Apache License 2.0
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* Licensed under the Apache License, Version 2.0 (the "License");
7 !* you may not use this file except in compliance with the License.
8 !* You may obtain a copy of the License at
9 !*
10 !* http://www.apache.org/licenses/LICENSE-2.0
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 !* PARTICULAR PURPOSE. See the License for the specific language
16 !* governing permissions and limitations under the License.
17 !***********************************************************************
18 !> @defgroup axis_utils2_mod axis_utils2_mod
19 !> @ingroup axis_utils
20 !> @brief A set of utilities for manipulating axes and extracting axis attributes.
21 !! FMS2_IO equivalent version of @ref axis_utils_mod.
22 !> @author M.J. Harrison
23 
24 !> @addtogroup axis_utils2_mod
25 !> @{
26 module axis_utils2_mod
27  use mpp_mod, only: mpp_error, fatal, stdout
28  use fms_mod, only: lowercase, uppercase, string_array_index, fms_error_handler
29  use fms2_io_mod, only: fmsnetcdfdomainfile_t, variable_att_exists, fmsnetcdffile_t, &
30  get_variable_num_dimensions, get_variable_attribute, &
31  get_variable_size, read_data, variable_exists
32  use platform_mod, only: r4_kind, r8_kind
33 
34  implicit none
35 
38 
39  private
40 
41  integer, parameter :: maxatts = 100
42  real(r8_kind), parameter :: epsln = 1.e-10_r8_kind
43  real(r8_kind), parameter :: fp5 = 0.5_r8_kind, f360 = 360.0_r8_kind
44 
45 !> @}
46 ! Include variable "version" to be written to log file.
47 #include<file_version.h>
48 
49  !> Perform 1D interpolation between grids.
50  !!
51  !> Data and grids can have 1, 2, or 3 dimensions.
52  !! @param grid1 grid for data1
53  !! @param grid2 grid for data2
54  !! @param data1 Data to interpolate
55  !! @param [inout] data2 Interpolated data
56  !! @param method Either "linear" or "cubic_spline" interpolation method, default="linear"
57  !! @ingroup axis_utils2_mod
58 
59  interface axis_edges
60  module procedure axis_edges_r4, axis_edges_r8
61  end interface axis_edges
62 
63  interface lon_in_range
64  module procedure lon_in_range_r4, lon_in_range_r8
65  end interface lon_in_range
66 
67  interface frac_index
68  module procedure frac_index_r4, frac_index_r8
69  end interface frac_index
70 
71  interface nearest_index
72  module procedure nearest_index_r4, nearest_index_r8
73  end interface nearest_index
74 
75  interface tranlon
76  module procedure tranlon_r4, tranlon_r8
77  end interface tranlon
78 
79  interface interp_1d_linear
80  module procedure interp_1d_linear_r4, interp_1d_linear_r8
81  end interface interp_1d_linear
82 
84  module procedure interp_1d_cubic_spline_r4, interp_1d_cubic_spline_r8
85  end interface interp_1d_cubic_spline
86 
87  interface interp_1d
88  module procedure interp_1d_1d_r4, interp_1d_1d_r8
89  module procedure interp_1d_2d_r4, interp_1d_2d_r8
90  module procedure interp_1d_3d_r4, interp_1d_3d_r8
91  end interface interp_1d
92 
93  interface find_index
94  module procedure find_index_r4, find_index_r8
95  end interface find_index
96 
97 !> @addtogroup axis_utils2_mod
98 !> @{
99 
100 contains
101 
102  !> @brief Returns X,Y,Z or T cartesian attribute
103  subroutine get_axis_cart(fileobj, axisname, cart)
104  type(fmsnetcdffile_t), intent(in) :: fileobj !< file object to read from
105  character(len=*), intent(in) :: axisname !< name of axis to retrieve
106  character(len=1), intent(out) :: cart !< Returned attribute axis
107 
108  character(len=1) :: axis_cart
109  character(len=16), dimension(2) :: lon_names, lat_names
110  character(len=16), dimension(3) :: z_names
111  character(len=16), dimension(2) :: t_names
112  character(len=16), dimension(3) :: lon_units, lat_units
113  character(len=8) , dimension(4) :: z_units
114  character(len=3) , dimension(6) :: t_units
115  character(len=32) :: name
116  integer :: i
117 
118  lon_names = (/'lon','x '/)
119  lat_names = (/'lat','y '/)
120  z_names = (/'depth ','height','z '/)
121  t_names = (/'time','t '/)
122  lon_units = (/'degrees_e ', 'degrees_east', 'degreese '/)
123  lat_units = (/'degrees_n ', 'degrees_north', 'degreesn '/)
124  z_units = (/'cm ','m ','pa ','hpa'/)
125  t_units = (/'sec', 'min','hou','day','mon','yea'/)
126 
127  cart = "N"
128  if (variable_exists(fileobj, axisname)) then
129  if (variable_att_exists(fileobj, axisname, "cartesian_axis")) then
130  call get_variable_attribute(fileobj, axisname, "cartesian_axis", cart(1:1))
131  elseif (variable_att_exists(fileobj, axisname, "axis")) then
132  call get_variable_attribute(fileobj, axisname, "axis", cart(1:1))
133  endif
134  axis_cart = uppercase(cart)
135  if (axis_cart .eq. 'X' .or. axis_cart .eq. 'Y' .or. axis_cart .eq. 'Z' &
136  .or. axis_cart .eq. 'T') then
137  cart = axis_cart
138  return
139  endif
140  endif
141 
142  if (cart /= 'X' .and. cart /= 'Y' .and. cart /= 'Z' .and. cart /= 'T') then
143  name = lowercase(axisname)
144  do i=1,size(lon_names(:))
145  if (trim(name(1:3)) == trim(lon_names(i))) cart = 'X'
146  enddo
147  do i=1,size(lat_names(:))
148  if (trim(name(1:3)) == trim(lat_names(i))) cart = 'Y'
149  enddo
150  do i=1,size(z_names(:))
151  if (trim(name) == trim(z_names(i))) cart = 'Z'
152  enddo
153  do i=1,size(t_names(:))
154  if (trim(name) == t_names(i)) cart = 'T'
155  enddo
156  end if
157 
158  if (cart /= 'X' .and. cart /= 'Y' .and. cart /= 'Z' .and. cart /= 'T') then
159  name = lowercase(axisname)
160  do i=1,size(lon_units(:))
161  if (trim(name) == trim(lon_units(i))) cart = 'X'
162  enddo
163  do i=1,size(lat_units(:))
164  if (trim(name) == trim(lat_units(i))) cart = 'Y'
165  enddo
166  do i=1,size(z_units(:))
167  if (trim(name) == trim(z_units(i))) cart = 'Z'
168  enddo
169  do i=1,size(t_units(:))
170  if (name(1:3) == trim(t_units(i))) cart = 'T'
171  enddo
172  end if
173  end subroutine get_axis_cart
174 
175  !> @brief Checks if 'modulo' variable exists for a given axis.
176  !!
177  !> @return true if modulo variable exists in fileobj for the given axis name.
178  function get_axis_modulo(fileobj, axisname)
179  type(fmsnetcdffile_t), intent(in) :: fileobj
180  character(len=*), intent(in) :: axisname
181  logical :: get_axis_modulo
182 
183  get_axis_modulo = variable_att_exists(fileobj, axisname, "modulo")
184  end function get_axis_modulo
185 
186  !> @return true if modulo_beg and modulo_end exist in fileobj with the given
187  !! axis, and returns their values in tbeg and tend.
188  function get_axis_modulo_times(fileobj, axisname, tbeg, tend)
189  type(fmsnetcdffile_t), intent(in) :: fileobj
190  character(len=*), intent(in) :: axisname
191  character(len=*), intent(out) :: tbeg, tend
192  logical :: get_axis_modulo_times
193  logical :: found_tbeg, found_tend
194 
195  found_tbeg = variable_att_exists(fileobj, axisname, "modulo_beg")
196  found_tend = variable_att_exists(fileobj, axisname, "modulo_end")
197 
198  if (found_tbeg .and. .not. found_tend) then
199  call mpp_error(fatal,'error in get: Found modulo_beg but not modulo_end')
200  endif
201  if (.not. found_tbeg .and. found_tend) then
202  call mpp_error(fatal,'error in get: Found modulo_end but not modulo_beg')
203  endif
204 
205  if (found_tbeg) then
206  call get_variable_attribute(fileobj, axisname, "modulo_beg", tbeg)
207  call get_variable_attribute(fileobj, axisname, "modulo_end", tend)
208  else
209  tbeg = ""
210  tend = ""
211  endif
212  get_axis_modulo_times = found_tbeg
213  end function get_axis_modulo_times
214 
215 #include "axis_utils2_r4.fh"
216 #include "axis_utils2_r8.fh"
217 
218 end module axis_utils2_mod
219 !> @}
220 ! close documentation grouping
subroutine, public get_axis_cart(fileobj, axisname, cart)
Returns X,Y,Z or T cartesian attribute.
logical function, public get_axis_modulo(fileobj, axisname)
Checks if 'modulo' variable exists for a given axis.
logical function, public get_axis_modulo_times(fileobj, axisname, tbeg, tend)
Perform 1D interpolation between grids.
Definition: axis_utils2.F90:59
Read data from a defined field in a file.
Definition: fms2_io.F90:291
logical function, public string_array_index(string, string_array, index)
match the input character string to a string in an array/list of character strings
Definition: fms.F90:673
logical function, public fms_error_handler(routine, message, err_msg)
Facilitates the control of fatal error conditions.
Definition: fms.F90:468
integer function stdout()
This function returns the current standard fortran unit numbers for output.
Definition: mpp_util.inc:42
Error handler.
Definition: mpp.F90:381