portedportable, not yet portedexecuted, not portableexecutable, not hit by this run
| 1 | ! This file is part of MOM6, the Modular Ocean Model version 6. | |
| 2 | ! See the LICENSE file for licensing information. | |
| 3 | ! SPDX-License-Identifier: Apache-2.0 | |
| 4 | ||
| 5 | !> This module wraps the FMS temporal and spatial interpolation routines | |
| 6 | module MOM_interp_infra | |
| 7 | ||
| 8 | use MOM_domain_infra, only : MOM_domain_type, domain2d | |
| 9 | use MOM_io_infra, only : axistype | |
| 10 | use MOM_io_infra, only : set_axis_data | |
| 11 | use MOM_time_manager, only : time_type | |
| 12 | use MOM_error_infra, only : MOM_error => MOM_err, FATAL | |
| 13 | use MOM_string_functions, only : lowercase | |
| 14 | use horiz_interp_mod, only : horiz_interp_new, horiz_interp, horiz_interp_init, horiz_interp_type | |
| 15 | use netcdf_io_mod, only : FmsNetcdfFile_t, netcdf_file_open, netcdf_file_close | |
| 16 | use netcdf_io_mod, only : get_num_variables, get_variable_names | |
| 17 | use time_interp_external2_mod, only : time_interp_external | |
| 18 | use time_interp_external2_mod, only : init_external_field, time_interp_external_init | |
| 19 | use time_interp_external2_mod, only : get_external_field_size | |
| 20 | use time_interp_external2_mod, only : get_external_field_missing | |
| 21 | ||
| 22 | ! Use primitive netCDF, to replicate get_var_axes_info() | |
| 23 | use netcdf, only : nf90_open | |
| 24 | use netcdf, only : nf90_close | |
| 25 | use netcdf, only : nf90_inq_varid | |
| 26 | use netcdf, only : nf90_inquire_variable | |
| 27 | use netcdf, only : nf90_inquire_dimension | |
| 28 | use netcdf, only : nf90_get_var | |
| 29 | use netcdf, only : NF90_NOWRITE | |
| 30 | use netcdf, only : NF90_NOERR | |
| 31 | ||
| 32 | ||
| 33 | implicit none ; private | |
| 34 | ||
| 35 | public :: horiz_interp_type, horizontal_interp_init | |
| 36 | public :: time_interp_extern, init_extern_field, time_interp_extern_init | |
| 37 | public :: get_external_field_info | |
| 38 | public :: run_horiz_interp, build_horiz_interp_weights | |
| 39 | public :: external_field | |
| 40 | ||
| 41 | !< Handle of an external field for interpolation | |
| 42 | type :: external_field | |
| 43 | private | |
| 44 | integer :: id | |
| 45 | !< FMS ID for the interpolated field | |
| 46 | character(len=:), allocatable :: filename | |
| 47 | !< Filename containing the field values | |
| 48 | character(len=:), allocatable :: label | |
| 49 | !< Field name in the file | |
| 50 | end type external_field | |
| 51 | ||
| 52 | !> Read a field based on model time, and rotate to the model domain. | |
| 53 | interface time_interp_extern | |
| 54 | module procedure time_interp_extern_0d | |
| 55 | module procedure time_interp_extern_2d | |
| 56 | module procedure time_interp_extern_3d | |
| 57 | end interface time_interp_extern | |
| 58 | ||
| 59 | !> perform horizontal interpolation of field | |
| 60 | interface run_horiz_interp | |
| 61 | module procedure horiz_interp_from_weights_field2d | |
| 62 | module procedure horiz_interp_from_weights_field3d | |
| 63 | end interface | |
| 64 | ||
| 65 | !> build weights for horizontal interpolation of field | |
| 66 | interface build_horiz_interp_weights | |
| 67 | module procedure build_horiz_interp_weights_2d_to_2d | |
| 68 | end interface build_horiz_interp_weights | |
| 69 | ||
| 70 | contains | |
| 71 | ||
| 72 | !> Do any initialization for the horizontal interpolation | |
| 73 | 0 | subroutine horizontal_interp_init() |
| 74 | 0 | call horiz_interp_init() |
| 75 | 0 | end subroutine horizontal_interp_init |
| 76 | ||
| 77 | !> Do any initialization for the time and space interpolation infrastructure | |
| 78 | 1 | subroutine time_interp_extern_init() |
| 79 | 1 | call time_interp_external_init() |
| 80 | 1 | end subroutine time_interp_extern_init |
| 81 | ||
| 82 | !> perform horizontal interpolation of a 2d field using pre-computed weights | |
| 83 | !! source and destination coordinates are 2d | |
| 84 | 0 | subroutine horiz_interp_from_weights_field2d(Interp, data_in, data_out, verbose, mask_in, mask_out, & |
| 85 | missing_value, missing_permit, err_msg) | |
| 86 | ||
| 87 | type(horiz_interp_type), intent(in) :: Interp !< type containing interpolation options and weights | |
| 88 | real, dimension(:,:), intent(in) :: data_in !< input data | |
| 89 | real, dimension(:,:), intent(out) :: data_out !< output data | |
| 90 | integer, optional, intent(in) :: verbose !< verbosity level | |
| 91 | real, dimension(:,:), optional, intent(in) :: mask_in !< mask for input data | |
| 92 | real, dimension(:,:), optional, intent(out) :: mask_out !< mask for output data | |
| 93 | real, optional, intent(in) :: missing_value !< A value indicating missing data | |
| 94 | integer, optional, intent(in) :: missing_permit !< number of allowed points with | |
| 95 | !! missing value for interpolation (0-3) | |
| 96 | character(len=*), optional, intent(out) :: err_msg !< error message | |
| 97 | ||
| 98 | call horiz_interp(Interp, data_in, data_out, verbose, & | |
| 99 | mask_in, mask_out, missing_value, missing_permit, & | |
| 100 | 0 | err_msg, new_missing_handle=.true. ) |
| 101 | ||
| 102 | 0 | end subroutine horiz_interp_from_weights_field2d |
| 103 | ||
| 104 | !> perform horizontal interpolation of a 3d field using pre-computed weights | |
| 105 | !! source and destination coordinates are 2d | |
| 106 | 0 | subroutine horiz_interp_from_weights_field3d(Interp, data_in, data_out, verbose, mask_in, mask_out, & |
| 107 | missing_value, missing_permit, err_msg) | |
| 108 | ||
| 109 | type(horiz_interp_type), intent(in) :: Interp !< type containing interpolation options and weights | |
| 110 | real, dimension(:,:,:), intent(in) :: data_in !< input data | |
| 111 | real, dimension(:,:,:), intent(out) :: data_out !< output data | |
| 112 | integer, optional, intent(in) :: verbose !< verbosity level | |
| 113 | real, dimension(:,:,:), optional, intent(in) :: mask_in !< mask for input data | |
| 114 | real, dimension(:,:,:), optional, intent(out) :: mask_out !< mask for output data | |
| 115 | real, optional, intent(in) :: missing_value !< A value indicating missing data | |
| 116 | integer, optional, intent(in) :: missing_permit !< number of allowed points with | |
| 117 | !! missing value for interpolation (0-3) | |
| 118 | character(len=*), optional, intent(out) :: err_msg !< error message | |
| 119 | ||
| 120 | call horiz_interp(Interp, data_in, data_out, verbose, mask_in, mask_out, & | |
| 121 | 0 | missing_value, missing_permit, err_msg) |
| 122 | ||
| 123 | 0 | end subroutine horiz_interp_from_weights_field3d |
| 124 | ||
| 125 | ||
| 126 | !> build horizontal interpolation weights from source grid defined by 2d lon/lat to destination grid | |
| 127 | !! defined by 2d lon/lat | |
| 128 | 0 | subroutine build_horiz_interp_weights_2d_to_2d(Interp, lon_in, lat_in, lon_out, lat_out, & |
| 129 | verbose, interp_method, num_nbrs, max_dist, & | |
| 130 | 0 | src_modulo, mask_in, mask_out, & |
| 131 | is_latlon_in, is_latlon_out) | |
| 132 | ||
| 133 | type(horiz_interp_type), intent(inout) :: Interp !< type containing interpolation options and weights | |
| 134 | real, dimension(:,:), intent(in) :: lon_in !< input longitude 2d | |
| 135 | real, dimension(:,:), intent(in) :: lat_in !< input latitude 2d | |
| 136 | real, dimension(:,:), intent(in) :: lon_out !< output longitude 2d | |
| 137 | real, dimension(:,:), intent(in) :: lat_out !< output latitude 2d | |
| 138 | integer, optional, intent(in) :: verbose !< verbosity level | |
| 139 | character(len=*), optional, intent(in) :: interp_method !< interpolation method | |
| 140 | integer, optional, intent(in) :: num_nbrs !< number of nearest neighbors | |
| 141 | real, optional, intent(in) :: max_dist !< maximum region of influence | |
| 142 | logical, optional, intent(in) :: src_modulo !< periodicity of E-W boundary | |
| 143 | real, dimension(:,:), optional, intent(in) :: mask_in !< mask for input data | |
| 144 | real, dimension(:,:), optional, intent(inout) :: mask_out !< mask for output data | |
| 145 | logical, optional, intent(in) :: is_latlon_in !< input grid is regular lat/lon grid | |
| 146 | logical, optional, intent(in) :: is_latlon_out !< output grid is regular lat/lon grid | |
| 147 | ||
| 148 | call horiz_interp_new(Interp, lon_in, lat_in, lon_out, lat_out, & | |
| 149 | verbose, interp_method, num_nbrs, max_dist, & | |
| 150 | src_modulo, mask_in, mask_out, & | |
| 151 | 0 | is_latlon_in, is_latlon_out) |
| 152 | ||
| 153 | 0 | end subroutine build_horiz_interp_weights_2d_to_2d |
| 154 | ||
| 155 | ||
| 156 | !> get size of an external field from field index | |
| 157 | 0 | function get_extern_field_size(index) |
| 158 | ||
| 159 | integer, intent(in) :: index !< field index | |
| 160 | integer :: get_extern_field_size(4) !< field size | |
| 161 | ||
| 162 | 0 | get_extern_field_size = get_external_field_size(index) |
| 163 | ||
| 164 | end function get_extern_field_size | |
| 165 | ||
| 166 | ||
| 167 | !> get axes of an external field from field index | |
| 168 | 0 | function get_extern_field_axes(field) result(axes) |
| 169 | type(external_field), intent(in) :: field | |
| 170 | !< Field handle | |
| 171 | type(axistype), dimension(4) :: axes | |
| 172 | !< Field axes | |
| 173 | ||
| 174 | integer :: ndims | |
| 175 | ! Number of variable dimensions | |
| 176 | 0 | integer, allocatable :: dims(:) |
| 177 | ! netCDF dimension IDs of variable | |
| 178 | character(len=256) :: dim_name | |
| 179 | ! Dimension name | |
| 180 | integer :: dim_len | |
| 181 | ! Dimension length | |
| 182 | integer :: var_dim | |
| 183 | ! netCDF ID of the variable associated with dimension of the same name | |
| 184 | 0 | real, allocatable :: axis_points(:) |
| 185 | ! Axis values | |
| 186 | ||
| 187 | integer :: ncid | |
| 188 | ! netCDF file ID | |
| 189 | integer :: varid | |
| 190 | ! netCDF variable ID | |
| 191 | integer :: rc | |
| 192 | ! netCDF return code | |
| 193 | ||
| 194 | ! netCDF requires the following to be length-1 arrays | |
| 195 | integer :: nc_start(1) | |
| 196 | ! netCDF start index | |
| 197 | integer :: nc_count(1) | |
| 198 | ! netCDF index count | |
| 199 | ||
| 200 | integer :: d | |
| 201 | ! Dimension index | |
| 202 | character(len=2) :: d_str | |
| 203 | ! Display string of d | |
| 204 | ||
| 205 | ! This is a reimplementation of get_var_axes_info(), maybe it can be used | |
| 206 | ! by the existing get_var_axes_info() ? | |
| 207 | ||
| 208 | ! Open field%filename | |
| 209 | 0 | rc = nf90_open(trim(field%filename), NF90_NOWRITE, ncid) |
| 210 | 0 | if (rc /= NF90_NOERR) & |
| 211 | 0 | call MOM_error(FATAL, "Error opening file " // trim(field%filename) // ".") |
| 212 | ||
| 213 | ! Use field%label to get the netCDF varid | |
| 214 | 0 | rc = nf90_inq_varid(ncid, trim(field%label), varid) |
| 215 | 0 | if (rc /= NF90_NOERR) & |
| 216 | call MOM_error(FATAL, "Error finding variable " // trim(field%label) & | |
| 217 | 0 | // " in " // trim(field%filename) // ".") |
| 218 | ||
| 219 | ! Use the varid to get the number of dims (ndims) and their IDs (dims(:)) | |
| 220 | ! Verify that ndims >= 3 | |
| 221 | 0 | rc = nf90_inquire_variable(ncid, varid, ndims=ndims) |
| 222 | 0 | if (rc /= NF90_NOERR) & |
| 223 | call MOM_error(FATAL, "Error querying variable " // trim(field%label) & | |
| 224 | 0 | // " in " // trim(field%filename) // ".") |
| 225 | ||
| 226 | 0 | if (ndims < 3) & |
| 227 | call MOM_error(FATAL, trim(field%label) // " in " // trim(field%filename) & | |
| 228 | 0 | // " has too few dimensions to be read as a 3D array.") |
| 229 | ||
| 230 | 0 | allocate(dims(ndims)) |
| 231 | ||
| 232 | 0 | rc = nf90_inquire_variable(ncid, varid, dimids=dims) |
| 233 | 0 | if (rc /= NF90_NOERR) & |
| 234 | call MOM_error(FATAL, "Error querying variable " // trim(field%label) & | |
| 235 | 0 | // " in " // trim(field%filename) // ".") |
| 236 | ||
| 237 | 0 | do d=1,ndims |
| 238 | ! Determine the name of each dimension | |
| 239 | 0 | rc = nf90_inquire_dimension(ncid, dims(d), dim_name, len=dim_len) |
| 240 | 0 | if (rc /= NF90_NOERR) then |
| 241 | 0 | write(d_str, '(i0)') d |
| 242 | call MOM_error(FATAL, "Error querying dimension " // trim(d_str) & | |
| 243 | // " of " // trim(field%label) // " in " // trim(field%filename) & | |
| 244 | 0 | // ".") |
| 245 | endif | |
| 246 | ||
| 247 | ! Now locate a variable with the same name as the dimension (e.g. "x") | |
| 248 | 0 | rc = nf90_inq_varid(ncid, dim_name, var_dim) |
| 249 | 0 | if (rc /= NF90_NOERR) & |
| 250 | call MOM_error(FATAL, "Error finding dimension variable " & | |
| 251 | // trim(dim_name) // " of " // trim(field%label) // " in " & | |
| 252 | 0 | // trim(field%filename)) |
| 253 | ||
| 254 | 0 | allocate(axis_points(dim_len)) |
| 255 | ||
| 256 | ! Get the dimensional axis values | |
| 257 | 0 | nc_start(1) = 1 |
| 258 | 0 | nc_count(1) = dim_len |
| 259 | 0 | rc = nf90_get_var(ncid, var_dim, axis_points, nc_start, nc_count) |
| 260 | 0 | if (rc /= NF90_NOERR) & |
| 261 | call MOM_error(FATAL, "Error reading dimension " // trim(dim_name) & | |
| 262 | // " axis data of " // trim(field%label) // " in " & | |
| 263 | 0 | // trim(field%filename)) |
| 264 | ||
| 265 | ! write via set_axis_info() equivalent for axistype | |
| 266 | 0 | call set_axis_data(axes(d), dim_name, axis_points) |
| 267 | ||
| 268 | 0 | deallocate(axis_points) |
| 269 | enddo | |
| 270 | ||
| 271 | 0 | deallocate(dims) |
| 272 | ||
| 273 | ! Close external file | |
| 274 | 0 | rc = nf90_close(ncid) |
| 275 | 0 | if (rc /= NF90_NOERR) & |
| 276 | 0 | call MOM_error(FATAL, "Error closing file "//trim(field%filename)//".") |
| 277 | ||
| 278 | 0 | end function get_extern_field_axes |
| 279 | ||
| 280 | ||
| 281 | !> get missing value of an external field from field index | |
| 282 | 0 | function get_extern_field_missing(index) |
| 283 | ||
| 284 | integer, intent(in) :: index !< field index | |
| 285 | real :: get_extern_field_missing !< field missing value | |
| 286 | ||
| 287 | 0 | get_extern_field_missing = get_external_field_missing(index) |
| 288 | ||
| 289 | 0 | end function get_extern_field_missing |
| 290 | ||
| 291 | ||
| 292 | !> Get information about the external fields. | |
| 293 | 0 | subroutine get_external_field_info(field, size, axes, missing) |
| 294 | type(external_field), intent(in) :: field | |
| 295 | !< handle for time interpolated external field returned from a previous | |
| 296 | !! call to init_external_field() | |
| 297 | integer, optional, intent(inout) :: size(4) | |
| 298 | !< Dimension sizes for the input data | |
| 299 | type(axistype), optional, intent(inout) :: axes(4) | |
| 300 | !< Axis types for the input data | |
| 301 | real, optional, intent(inout) :: missing | |
| 302 | !< Missing value for the input data | |
| 303 | ||
| 304 | 0 | if (present(size)) then |
| 305 | 0 | size(:) = get_extern_field_size(field%id) |
| 306 | endif | |
| 307 | ||
| 308 | 0 | if (present(axes)) then |
| 309 | 0 | axes(:) = get_extern_field_axes(field) |
| 310 | endif | |
| 311 | ||
| 312 | 0 | if (present(missing)) then |
| 313 | 0 | missing = get_extern_field_missing(field%id) |
| 314 | endif | |
| 315 | 0 | end subroutine get_external_field_info |
| 316 | ||
| 317 | ||
| 318 | !> Read a scalar field based on model time. | |
| 319 | 0 | subroutine time_interp_extern_0d(field, time, data_in, verbose) |
| 320 | type(external_field), intent(in) :: field !< Handle for time interpolated field | |
| 321 | type(time_type), intent(in) :: time !< The target time for the data | |
| 322 | real, intent(inout) :: data_in !< The interpolated value | |
| 323 | logical, optional, intent(in) :: verbose !< If true, write verbose output for debugging | |
| 324 | ||
| 325 | 0 | call time_interp_external(field%id, time, data_in, verbose=verbose) |
| 326 | 0 | end subroutine time_interp_extern_0d |
| 327 | ||
| 328 | ||
| 329 | !> Read a 2d field from an external based on model time, potentially including horizontal | |
| 330 | !! interpolation and rotation of the data | |
| 331 | 0 | subroutine time_interp_extern_2d(field, time, data_in, interp, verbose, horz_interp, mask_out) |
| 332 | type(external_field), intent(in) :: field !< Handle for time interpolated field | |
| 333 | type(time_type), intent(in) :: time !< The target time for the data | |
| 334 | real, dimension(:,:), intent(inout) :: data_in !< The array in which to store the interpolated values | |
| 335 | integer, optional, intent(in) :: interp !< A flag indicating the temporal interpolation method | |
| 336 | logical, optional, intent(in) :: verbose !< If true, write verbose output for debugging | |
| 337 | type(horiz_interp_type), & | |
| 338 | optional, intent(in) :: horz_interp !< A structure to control horizontal interpolation | |
| 339 | logical, dimension(:,:), & | |
| 340 | optional, intent(out) :: mask_out !< An array that is true where there is valid data | |
| 341 | ||
| 342 | call time_interp_external(field%id, time, data_in, interp=interp, verbose=verbose, & | |
| 343 | 0 | horz_interp=horz_interp, mask_out=mask_out) |
| 344 | 0 | end subroutine time_interp_extern_2d |
| 345 | ||
| 346 | ||
| 347 | !> Read a 3d field based on model time, and rotate to the model grid | |
| 348 | 0 | subroutine time_interp_extern_3d(field, time, data_in, interp, verbose, horz_interp, mask_out) |
| 349 | type(external_field), intent(in) :: field !< Handle for time interpolated field | |
| 350 | type(time_type), intent(in) :: time !< The target time for the data | |
| 351 | real, dimension(:,:,:), intent(inout) :: data_in !< The array in which to store the interpolated values | |
| 352 | integer, optional, intent(in) :: interp !< A flag indicating the temporal interpolation method | |
| 353 | logical, optional, intent(in) :: verbose !< If true, write verbose output for debugging | |
| 354 | type(horiz_interp_type), & | |
| 355 | optional, intent(in) :: horz_interp !< A structure to control horizontal interpolation | |
| 356 | logical, dimension(:,:,:), & | |
| 357 | optional, intent(out) :: mask_out !< An array that is true where there is valid data | |
| 358 | ||
| 359 | call time_interp_external(field%id, time, data_in, interp=interp, verbose=verbose, & | |
| 360 | 0 | horz_interp=horz_interp, mask_out=mask_out) |
| 361 | 0 | end subroutine time_interp_extern_3d |
| 362 | ||
| 363 | ||
| 364 | !> initialize an external field | |
| 365 | 0 | function init_extern_field(file, fieldname, MOM_domain, domain, verbose, & |
| 366 | threading, ierr, ignore_axis_atts, correct_leap_year_inconsistency) & | |
| 367 | result(field) | |
| 368 | ||
| 369 | character(len=*), intent(in) :: file !< The name of the file to read | |
| 370 | character(len=*), intent(in) :: fieldname !< The name of the field in the file | |
| 371 | integer, optional, intent(in) :: threading !< A flag specifying whether the root PE reads | |
| 372 | !! the data and broadcasts it (SINGLE_FILE) or all | |
| 373 | !! processors read (MULTIPLE, the default). | |
| 374 | logical, optional, intent(in) :: verbose !< If true, write verbose output for debugging | |
| 375 | type(domain2d), optional, intent(in) :: domain !< A domain2d type that describes the decomposition | |
| 376 | type(MOM_domain_type), & | |
| 377 | optional, intent(in) :: MOM_Domain !< A MOM_Domain that describes the decomposition | |
| 378 | integer, optional, intent(out) :: ierr !< Returns a non-zero error code in case of failure | |
| 379 | logical, optional, intent(in) :: ignore_axis_atts !< If present and true, do not issue a | |
| 380 | !! fatal error if the axis Cartesian attribute is | |
| 381 | !! not set to a recognized value. | |
| 382 | logical, optional, intent(in) :: correct_leap_year_inconsistency !< If present and true, | |
| 383 | !! then if, (1) a calendar containing leap years | |
| 384 | !! is in use, and (2) the modulo time period of the | |
| 385 | !! data is an integer number of years, then map | |
| 386 | !! a model date of Feb 29. onto a common year on Feb. 28. | |
| 387 | type(external_field) :: field !< Handle to external field | |
| 388 | ||
| 389 | 0 | type(FmsNetcdfFile_t) :: extern_file |
| 390 | ! Local instance of netCDF file used to locate case-insensitive field name | |
| 391 | integer :: num_fields | |
| 392 | ! Number of fields in external file | |
| 393 | 0 | character(len=256), allocatable :: extern_fieldnames(:) |
| 394 | ! List of field names in file | |
| 395 | ! NOTE: length should NF90_MAX_NAME, but I don't know how to read it | |
| 396 | character(len=:), allocatable :: label | |
| 397 | ! Case-insensitive match to fieldname in file | |
| 398 | logical :: rc | |
| 399 | ! Return status | |
| 400 | integer :: i | |
| 401 | ! Loop index | |
| 402 | ||
| 403 | 0 | field%filename = file |
| 404 | ||
| 405 | ! FMS2's init_external_field is case sensitive, so we must replicate the | |
| 406 | ! case-insensitivity of FMS1. This requires opening the file twice. | |
| 407 | ||
| 408 | 0 | rc = netcdf_file_open(extern_file, file, 'read') |
| 409 | 0 | if (.not. rc) then |
| 410 | call MOM_error(FATAL, 'init_extern_file: file ' // trim(file) & | |
| 411 | 0 | // ' could not be opened.') |
| 412 | endif | |
| 413 | ||
| 414 | ! TODO: broadcast = .false.? | |
| 415 | 0 | num_fields = get_num_variables(extern_file) |
| 416 | ||
| 417 | 0 | allocate(extern_fieldnames(num_fields)) |
| 418 | 0 | call get_variable_names(extern_file, extern_fieldnames) |
| 419 | ||
| 420 | 0 | do i = 1, num_fields |
| 421 | 0 | if (lowercase(extern_fieldnames(i)) == lowercase(fieldname)) then |
| 422 | 0 | field%label = extern_fieldnames(i) |
| 423 | 0 | exit |
| 424 | endif | |
| 425 | enddo | |
| 426 | ||
| 427 | 0 | call netcdf_file_close(extern_file) |
| 428 | ||
| 429 | 0 | if (.not. allocated(field%label)) then |
| 430 | call MOM_error(FATAL, 'init_extern_field: field ' // trim(fieldname) & | |
| 431 | 0 | // ' not found in ' // trim(file) // '.') |
| 432 | endif | |
| 433 | ||
| 434 | ! Pass to FMS2 implementation of init_external_field | |
| 435 | ||
| 436 | ! NOTE: external fields are currently assumed to be on-grid, which holds | |
| 437 | ! across the current codebase. In the future, we may need to either enforce | |
| 438 | ! this or somehow relax this requirement. | |
| 439 | ||
| 440 | 0 | if (present(MOM_Domain)) then |
| 441 | field%id = init_external_field(file, field%label, domain=MOM_domain%mpp_domain, & | |
| 442 | verbose=verbose, ierr=ierr, ignore_axis_atts=ignore_axis_atts, & | |
| 443 | correct_leap_year_inconsistency=correct_leap_year_inconsistency, & | |
| 444 | 0 | ongrid=.true.) |
| 445 | else | |
| 446 | field%id = init_external_field(file, field%label, domain=domain, & | |
| 447 | verbose=verbose, ierr=ierr, ignore_axis_atts=ignore_axis_atts, & | |
| 448 | correct_leap_year_inconsistency=correct_leap_year_inconsistency, & | |
| 449 | 0 | ongrid=.true.) |
| 450 | endif | |
| 451 | 0 | end function init_extern_field |
| 452 | ||
| 453 | 0 | end module MOM_interp_infra |