!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! !!
!! GNU General Public License !!
!! !!
!! This file is part of the Flexible Modeling System (FMS). !!
!! !!
!! FMS is free software; you can redistribute it and/or modify !!
!! it and are expected to follow the terms of the GNU General Public !!
!! License as published by the Free Software Foundation. !!
!! !!
!! FMS is distributed in the hope that it will be useful, !!
!! but WITHOUT ANY WARRANTY; 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 General Public License !!
!! along with FMS; if not, write to: !!
!! Free Software Foundation, Inc. !!
!! 59 Temple Place, Suite 330 !!
!! Boston, MA 02111-1307 USA !!
!! or see: !!
!! http://www.gnu.org/licenses/gpl.txt !!
!! !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module data_override_mod
!
!
! G.T. Nong
!
!
!
! M.J. Harrison
!
!
!
! M. Winton
!
!
! Given a gridname, fieldname and model time this routine will get data in a file whose
! path is described in a user-provided data_table, do spatial and temporal interpolation if
! necessary to convert data to model's grid and time.
!
! Before using data_override a data_table must be created with the following entries:
! gridname, fieldname_code, fieldname_file, file_name, ongrid, factor.
!
! More explainations about data_table entries can be found in the source code (defining data_type)
!
! If user wants to override fieldname_code with a const, set fieldname_file in data_table = ""
! and factor = const
!
! If user wants to override fieldname_code with data from a file, set fieldname_file = name in
! the netCDF data file, factor then will be for unit conversion (=1 if no conversion required)
!
! A field can be overriden globally (by default) or users can specify one or two regions in which
! data_override will take place, field values outside the region will not be affected.
!
#include
use platform_mod, only: r8_kind
use constants_mod, only: PI
use mpp_io_mod, only: axistype,mpp_close,mpp_open,mpp_get_axis_data,MPP_RDONLY,MPP_ASCII
use mpp_mod, only : mpp_error,FATAL,WARNING,mpp_pe,stdout,stdlog,mpp_root_pe, NOTE, mpp_min, mpp_max, mpp_chksum
use horiz_interp_mod, only : horiz_interp_init, horiz_interp_new, horiz_interp_type, &
assignment(=), horiz_interp_del
use time_interp_external_mod, only:time_interp_external_init, time_interp_external, &
init_external_field, get_external_field_size
use fms_io_mod, only: field_size, read_data, fms_io_init,get_mosaic_tile_grid
use fms_mod, only: write_version_number, field_exist, lowercase, file_exist
use axis_utils_mod, only: get_axis_bounds
use mpp_domains_mod, only : domain2d, mpp_get_compute_domain, NULL_DOMAIN2D,operator(.NE.),operator(.EQ.)
use mpp_domains_mod, only : mpp_copy_domain, mpp_get_global_domain
use mpp_domains_mod, only : mpp_get_data_domain, mpp_set_compute_domain, mpp_set_data_domain
use mpp_domains_mod, only : mpp_set_global_domain, mpp_deallocate_domain
use time_manager_mod, only: time_type
implicit none
private
character(len=128) :: version = '$Id: data_override.F90,v 16.0.4.1.2.1.2.1.2.1.2.1 2009/08/24 13:43:55 z1l Exp $'
character(len=128) :: tagname = '$Name: mom4p1_pubrel_dec2009_nnz $'
type data_type_lima
character(len=3) :: gridname
character(len=128) :: fieldname_code !fieldname used in user's code (model)
character(len=128) :: fieldname_file ! fieldname used in the netcdf data file
character(len=512) :: file_name ! name of netCDF data file
logical :: ongrid ! true if data is on model's grid, false otherwise
real :: factor ! For unit conversion, default=1, see OVERVIEW above
end type data_type_lima
type data_type
character(len=3) :: gridname
character(len=128) :: fieldname_code !fieldname used in user's code (model)
character(len=128) :: fieldname_file ! fieldname used in the netcdf data file
character(len=512) :: file_name ! name of netCDF data file
character(len=128) :: interpol_method ! interpolation method (default "bilinear")
real :: factor ! For unit conversion, default=1, see OVERVIEW above
end type data_type
type override_type
character(len=3) :: gridname
character(len=128) :: fieldname
integer :: t_index !index for time interp
type(horiz_interp_type) :: horz_interp ! index for horizontal spatial interp
integer :: dims(4) ! dimensions(x,y,z,t) of the field in filename
integer :: comp_domain(4) ! istart,iend,jstart,jend for compute domain
logical, dimension(:,:), _ALLOCATABLE :: region1 ! mask for regional override
logical, dimension(:,:), _ALLOCATABLE :: region2 ! mask for regional override
end type override_type
integer, parameter :: max_table=100, max_array=100
integer :: table_size ! actual size of data table
integer, parameter :: ANNUAL=1, MONTHLY=2, DAILY=3, HOURLY=4, UNDEF=-1
real, parameter :: tpi=2*PI
real :: deg_to_radian, radian_to_deg
logical :: module_is_initialized = .FALSE.
type(domain2D),save :: ocn_domain,atm_domain,lnd_domain, ice_domain
real, dimension(:,:), target, allocatable :: lon_local_ocn, lat_local_ocn
real, dimension(:,:), target, allocatable :: lon_local_atm, lat_local_atm
real, dimension(:,:), target, allocatable :: lon_local_ice, lat_local_ice
real, dimension(:,:), target, allocatable :: lon_local_lnd, lat_local_lnd
real :: min_glo_lon_ocn, max_glo_lon_ocn
real :: min_glo_lon_atm, max_glo_lon_atm
real :: min_glo_lon_lnd, max_glo_lon_lnd
real :: min_glo_lon_ice, max_glo_lon_ice
integer:: num_fields = 0 ! number of fields in override_array already processed
type(data_type), dimension(max_table) :: data_table ! user-provided data table
type(data_type) :: default_table
type(override_type), dimension(max_array), save :: override_array ! to store processed fields
type(override_type), save :: default_array
logical :: atm_on, ocn_on, lnd_on, ice_on
logical :: debug_data_override
logical :: grid_center_bug = .false.
namelist /data_override_nml/ debug_data_override, grid_center_bug
interface data_override
module procedure data_override_0d
module procedure data_override_2d
module procedure data_override_3d
end interface
public :: data_override_init, data_override
contains
!===============================================================================================
!
!
! Assign default values for default_table, get domain of component models,
! get global grids of component models.
! Users should call data_override_init before calling data_override
!
!
! call data_override_init
!
subroutine data_override_init(Atm_domain_in, Ocean_domain_in, Ice_domain_in, Land_domain_in)
type (domain2d), intent(in), optional :: Atm_domain_in
type (domain2d), intent(in), optional :: Ocean_domain_in, Ice_domain_in
type (domain2d), intent(in), optional :: Land_domain_in
!
! This subroutine should be called in coupler_init after
! (ocean/atmos/land/ice)_model_init have been called.
!
! data_override_init can be called more than once, in one call the user can pass
! up to 4 domains of component models, at least one domain must be present in
! any call
!
! Data_table is initialized here with default values. Users should provide "real" values
! that will override the default values. Real values can be given using data_table, each
! line of data_table contains one data_entry. Items of data_entry are comma separated.
!
!
character(len=128) :: grid_file = 'INPUT/grid_spec.nc'
integer :: is,ie,js,je,count
integer :: i, iunit, ntable, ntable_lima, ntable_new, unit,io_status
character(len=256) :: record
type(data_type_lima) :: data_entry_lima
type(data_type) :: data_entry
logical :: file_open
debug_data_override = .false.
call mpp_open(iunit, 'input.nml',form=MPP_ASCII,action=MPP_RDONLY)
read(iunit,data_override_nml,iostat=io_status)
unit = stdlog()
write(unit, data_override_nml)
if (io_status > 0) then
call mpp_error(FATAL,'data_override_init: Error reading data_override_nml')
endif
call mpp_close (iunit)
! if(module_is_initialized) return
atm_on = PRESENT(Atm_domain_in)
ocn_on = PRESENT(Ocean_domain_in)
lnd_on = PRESENT(Land_domain_in)
ice_on = PRESENT(Ice_domain_in)
if(.not. module_is_initialized) then
atm_domain = NULL_DOMAIN2D
ocn_domain = NULL_DOMAIN2D
lnd_domain = NULL_DOMAIN2D
ice_domain = NULL_DOMAIN2D
end if
if (atm_on) atm_domain = Atm_domain_in
if (ocn_on) ocn_domain = Ocean_domain_in
if (lnd_on) lnd_domain = Land_domain_in
if (ice_on) ice_domain = Ice_domain_in
if(.not. module_is_initialized) then
call horiz_interp_init
radian_to_deg = 180./PI
deg_to_radian = PI/180.
call write_version_number (version, tagname)
! Initialize user-provided data table
default_table%gridname = 'none'
default_table%fieldname_code = 'none'
default_table%fieldname_file = 'none'
default_table%file_name = 'none'
default_table%factor = 1.
default_table%interpol_method = 'bilinear'
do i = 1,max_table
data_table(i) = default_table
enddo
! Read coupler_table
call mpp_open(iunit, 'data_table', action=MPP_RDONLY)
ntable = 0
ntable_lima = 0
ntable_new = 0
do while (ntable <= max_table)
read(iunit,'(a)',end=100) record
if (record(1:1) == '#') cycle
if (record(1:10) == ' ') cycle
ntable=ntable+1
if (index(lowercase(record), ".false.") .ne. 0 .or. index(lowercase(record), ".true.") .ne. 0 ) then ! old format
ntable_lima = ntable_lima + 1
read(record,*,err=99) data_entry_lima
data_entry%gridname = data_entry_lima%gridname
data_entry%fieldname_code = data_entry_lima%fieldname_code
data_entry%fieldname_file = data_entry_lima%fieldname_file
data_entry%file_name = data_entry_lima%file_name
data_entry%factor = data_entry_lima%factor
if(data_entry_lima%ongrid) then
data_entry%interpol_method = 'none'
else
data_entry%interpol_method = 'bilinear'
endif
else ! new format
ntable_new=ntable_new+1
read(record,*,err=99) data_entry
data_entry%interpol_method = lowercase(data_entry%interpol_method)
if (data_entry%interpol_method == 'default') then
data_entry%interpol_method = default_table%interpol_method
endif
if (.not.(data_entry%interpol_method == 'default' .or. &
data_entry%interpol_method == 'bicubic' .or. &
data_entry%interpol_method == 'bilinear' .or. &
data_entry%interpol_method == 'none')) then
unit = stdout()
write(unit,*)" gridname is ", trim(data_entry%gridname)
write(unit,*)" fieldname_code is ", trim(data_entry%fieldname_code)
write(unit,*)" fieldname_file is ", trim(data_entry%fieldname_file)
write(unit,*)" file_name is ", trim(data_entry%file_name)
write(unit,*)" factor is ", data_entry%factor
write(unit,*)" interpol_method is ", trim(data_entry%interpol_method)
call mpp_error(FATAL, 'data_override_mod: invalid last entry in data_override_table, ' &
//'its value should be "default", "bicubic", "bilinear" or "none" ')
endif
endif
data_table(ntable) = data_entry
enddo
call mpp_error(FATAL,'too many enries in data_table')
99 call mpp_error(FATAL,'error in data_table format')
100 continue
table_size = ntable
if(ntable_new*ntable_lima /= 0) call mpp_error(FATAL, &
'data_override_mod: New and old formats together in same data_table not supported')
call mpp_close(iunit)
! Initialize override array
default_array%gridname = 'NONE'
default_array%fieldname = 'NONE'
default_array%t_index = -1
default_array%dims = -1
default_array%comp_domain = -1
do i = 1, max_array
override_array(i) = default_array
enddo
call time_interp_external_init
endif
module_is_initialized = .TRUE.
if ( .NOT. (atm_on .or. ocn_on .or. lnd_on .or. ice_on)) return
call fms_io_init
! Test if grid_file is already opened
inquire (file=trim(grid_file), opened=file_open)
if(file_open) call mpp_error(FATAL, trim(grid_file)//' already opened')
if(field_exist(grid_file, "x_T" ) .OR. field_exist(grid_file, "geolon_t" ) ) then
if (atm_on) then
call mpp_get_compute_domain( atm_domain,is,ie,js,je)
allocate(lon_local_atm(is:ie,js:je), lat_local_atm(is:ie,js:je))
call get_grid_version_1(grid_file, 'atm', atm_domain, is, ie, js, je, lon_local_atm, lat_local_atm, &
min_glo_lon_atm, max_glo_lon_atm )
endif
if (ocn_on) then
call mpp_get_compute_domain( ocn_domain,is,ie,js,je)
allocate(lon_local_ocn(is:ie,js:je), lat_local_ocn(is:ie,js:je))
call get_grid_version_1(grid_file, 'ocn', ocn_domain, is, ie, js, je, lon_local_ocn, lat_local_ocn, &
min_glo_lon_ocn, max_glo_lon_ocn )
endif
if (lnd_on) then
call mpp_get_compute_domain( lnd_domain,is,ie,js,je)
allocate(lon_local_lnd(is:ie,js:je), lat_local_lnd(is:ie,js:je))
call get_grid_version_1(grid_file, 'lnd', lnd_domain, is, ie, js, je, lon_local_lnd, lat_local_lnd, &
min_glo_lon_lnd, max_glo_lon_lnd )
endif
if (ice_on) then
call mpp_get_compute_domain( ice_domain,is,ie,js,je)
allocate(lon_local_ice(is:ie,js:je), lat_local_ice(is:ie,js:je))
call get_grid_version_1(grid_file, 'ice', ice_domain, is, ie, js, je, lon_local_ice, lat_local_ice, &
min_glo_lon_ice, max_glo_lon_ice )
endif
else if(field_exist(grid_file, "ocn_mosaic_file" ) .OR. field_exist(grid_file, "gridfiles" ) ) then
if(field_exist(grid_file, "gridfiles" ) ) then
count = 0
if (atm_on) count = count + 1
if (lnd_on) count = count + 1
if ( ocn_on .OR. ice_on ) count = count + 1
if(count .NE. 1) call mpp_error(FATAL, 'data_override_mod: the grid file is a solo mosaic, ' // &
'one and only one of atm_on, lnd_on or ice_on/ocn_on should be true')
endif
if (atm_on) then
call mpp_get_compute_domain(atm_domain,is,ie,js,je)
allocate(lon_local_atm(is:ie,js:je), lat_local_atm(is:ie,js:je))
call get_grid_version_2(grid_file, 'atm', atm_domain, is, ie, js, je, lon_local_atm, lat_local_atm, &
min_glo_lon_atm, max_glo_lon_atm )
endif
if (ocn_on) then
call mpp_get_compute_domain( ocn_domain,is,ie,js,je)
allocate(lon_local_ocn(is:ie,js:je), lat_local_ocn(is:ie,js:je))
call get_grid_version_2(grid_file, 'ocn', ocn_domain, is, ie, js, je, lon_local_ocn, lat_local_ocn, &
min_glo_lon_ocn, max_glo_lon_ocn )
endif
if (lnd_on) then
call mpp_get_compute_domain( lnd_domain,is,ie,js,je)
allocate(lon_local_lnd(is:ie,js:je), lat_local_lnd(is:ie,js:je))
call get_grid_version_2(grid_file, 'lnd', lnd_domain, is, ie, js, je, lon_local_lnd, lat_local_lnd, &
min_glo_lon_lnd, max_glo_lon_lnd )
endif
if (ice_on) then
call mpp_get_compute_domain( ice_domain,is,ie,js,je)
allocate(lon_local_ice(is:ie,js:je), lat_local_ice(is:ie,js:je))
call get_grid_version_2(grid_file, 'ocn', ice_domain, is, ie, js, je, lon_local_ice, lat_local_ice, &
min_glo_lon_ice, max_glo_lon_ice )
endif
else
call mpp_error(FATAL, 'data_override_mod: none of x_T, geolon_t, ocn_mosaic_file or gridfiles exist in '//trim(grid_file))
end if
end subroutine data_override_init
!
!===============================================================================================
subroutine check_grid_sizes(domain_name, Domain, nlon, nlat)
character(len=12), intent(in) :: domain_name
type (domain2d), intent(in) :: Domain
integer, intent(in) :: nlon, nlat
character(len=184) :: error_message
integer :: xsize, ysize
call mpp_get_global_domain(Domain, xsize=xsize, ysize=ysize)
if(nlon .NE. xsize .OR. nlat .NE. ysize) then
error_message = 'Error in data_override_init. Size of grid as specified by '// &
' does not conform to that specified by grid_spec.nc.'// &
' From : by From grid_spec.nc: by '
error_message( 59: 70) = domain_name
error_message(130:141) = domain_name
write(error_message(143:146),'(i4)') xsize
write(error_message(150:153),'(i4)') ysize
write(error_message(174:177),'(i4)') nlon
write(error_message(181:184),'(i4)') nlat
call mpp_error(FATAL,error_message)
endif
end subroutine check_grid_sizes
!===============================================================================================
subroutine get_domain(gridname, domain, comp_domain)
! Given a gridname, this routine returns the working domain associated with this gridname
character(len=3), intent(in) :: gridname
type(domain2D), intent(inout) :: domain
integer, intent(out), optional :: comp_domain(4) ! istart,iend,jstart,jend for compute domain
domain = NULL_DOMAIN2D
select case (gridname)
case('OCN')
domain = ocn_domain
case('ATM')
domain = atm_domain
case('LND')
domain = lnd_domain
case('ICE')
domain = ice_domain
case default
call mpp_error(FATAL,'error in data_override get_domain')
end select
if(domain .EQ. NULL_DOMAIN2D) call mpp_error(FATAL,'data_override: failure in get_domain')
if(present(comp_domain)) &
call mpp_get_compute_domain(domain,comp_domain(1),comp_domain(2),comp_domain(3),comp_domain(4))
end subroutine get_domain
!===============================================================================================
!
!
! This routine performs data override for 2D fields; for usage, see data_override_3d.
!
subroutine data_override_2d(gridname,fieldname,data_2D,time,override,region1,region2)
character(len=3), intent(in) :: gridname ! model grid ID
character(len=*), intent(in) :: fieldname ! field to override
logical, intent(out), optional :: override ! true if the field has been overriden succesfully
real, intent(in), optional :: region1(4),region2(4) !lat and lon of region where override is done
type(time_type), intent(in) :: time ! model time
real, dimension(:,:), intent(inout) :: data_2D !data returned by this call
! real, dimension(size(data_2D,1),size(data_2D,2),1) :: data_3D
real, dimension(:,:,:), allocatable :: data_3D
integer :: index1
integer :: i
!1 Look for the data file in data_table
if(PRESENT(override)) override = .false.
index1 = -1
do i = 1, table_size
if( trim(gridname) /= trim(data_table(i)%gridname)) cycle
if( trim(fieldname) /= trim(data_table(i)%fieldname_code)) cycle
index1 = i ! field found
exit
enddo
if(index1 .eq. -1) return ! NO override was performed
allocate(data_3D(size(data_2D,1),size(data_2D,2),1))
data_3D(:,:,1) = data_2D
call data_override_3d(gridname,fieldname,data_3D,time,override,region1,region2,data_index=index1)
data_2D(:,:) = data_3D(:,:,1)
deallocate(data_3D)
end subroutine data_override_2d
!
!===============================================================================================
!
!
! This routine performs data override for 3D fields
!
! call data_override(gridname,fieldname,data,time,override)
!
!
!
! Grid name (Ocean, Ice, Atmosphere, Land)
!
!
! Field name as used in the code (may be different from the name in NetCDF data file)
!
!
! array containing output data
!
!
! model time
!
!
! TRUE if the field is overriden, FALSE otherwise
!
!
! Restricts override to a rectangular region in lat,lon space.
! This may not be a rectangular region in i,j space when the model grid is tripolar.
! region1=(/lat_start, lat_end, lon_start, lon_end/)
! Clarification regarding longitude: lon_start may be greater than lon_end.
! The region overriden will be from lat_start eastward to lat_end.
! e.g. if lat_start,lat_end = 180.,0.0 then the western hemisphere will be overriden.
!
!
! A second region to override. May be present only if region1 is also present.
!
!
!
subroutine data_override_3d(gridname,fieldname_code,data1,time,override,region1,region2,data_index)
character(len=3), intent(in) :: gridname ! model grid ID
character(len=*), intent(in) :: fieldname_code ! field name as used in the model
logical, intent(out), optional :: override ! true if the field has been overriden succesfully
type(time_type), intent(in) :: time !(target) model time
real, intent(in), optional :: region1(4),region2(4) !lat and lon of regions where override is done
!Note: region2 can not exist without region1. In other words, if only one region is specified, it
! should be region1
integer, intent(in), optional :: data_index
real, dimension(:,:,:), intent(out) :: data1 !data returned by this call
real, dimension(:,:,:), allocatable :: data !temporary array for data
character(len=512) :: filename !file containing source data
character(len=128) :: fieldname ! fieldname used in the data file
integer :: i,j
integer :: dims(4)
integer :: index1 ! field index in data_table
integer :: id_time !index for time interp in override array
integer :: axis_sizes(4)
real, dimension(:),allocatable :: lon_in, lat_in !of the input (source) grid
real, dimension(:,:), pointer :: lon_local =>NULL(), &
lat_local =>NULL() !of output (target) grid cells
type(axistype) :: axis_centers(4), axis_bounds(4)
logical :: data_file_is_2D = .false. !data in netCDF file is 2D
logical :: ongrid, use_comp_domain
type(domain2D) :: domain
integer :: curr_position ! position of the field currently processed in override_array
real :: factor
integer, dimension(4) :: comp_domain = 0 ! istart,iend,jstart,jend for compute domain
integer :: ilocal, jlocal, dxsize, dysize
use_comp_domain = .false.
if(.not.module_is_initialized) &
call mpp_error(FATAL,'Error: need to call data_override_init first')
!1 Look for the data file in data_table
if(PRESENT(override)) override = .false.
if (present(data_index)) then
index1 = data_index
else
index1 = -1
do i = 1, table_size
if( trim(gridname) /= trim(data_table(i)%gridname)) cycle
if( trim(fieldname_code) /= trim(data_table(i)%fieldname_code)) cycle
index1 = i ! field found
exit
enddo
if(index1 .eq. -1) then
if(mpp_pe() == mpp_root_pe() .and. debug_data_override) &
call mpp_error(WARNING,'this field is NOT found in data_table: '//trim(fieldname_code))
return ! NO override was performed
endif
endif
if(present(region2) .and. .not. present(region1)) &
call mpp_error(FATAL,'data_override: region2 is specified without region1')
fieldname = data_table(index1)%fieldname_file ! fieldname in netCDF data file
factor = data_table(index1)%factor
if(fieldname == "") then
data1 = factor
if(PRESENT(override)) override = .true.
return
else
filename = data_table(index1)%file_name
if (filename == "") call mpp_error(FATAL,'data_override: filename not given in data_table')
endif
ongrid = (data_table(index1)%interpol_method == 'none')
!3 Check if fieldname has been previously processed
curr_position = -1
if(num_fields > 0 ) then
do i = 1, num_fields
if(trim(override_array(i)%gridname) /= trim(gridname)) cycle
if(trim(override_array(i)%fieldname) /= trim(fieldname_code)) cycle
curr_position = i
exit
enddo
endif
if(curr_position < 0) then ! the field has not been processed previously
num_fields = num_fields + 1
curr_position = num_fields
! Get working domain from model's gridname
call get_domain(gridname,domain,comp_domain)
dxsize = comp_domain(2)-comp_domain(1) + 1
dysize = comp_domain(4)-comp_domain(3) + 1
if(dxsize==size(data1,1) .and. dysize==size(data1,2)) use_comp_domain = .true.
if(present(region1)) then
allocate(override_array(curr_position)%region1(comp_domain(1):comp_domain(2), comp_domain(3):comp_domain(4)))
call get_region_bounds( &
gridname,comp_domain(1),comp_domain(2),comp_domain(3),comp_domain(4),region1,override_array(curr_position)%region1)
if(present(region2)) then
allocate(override_array(curr_position)%region2(comp_domain(1):comp_domain(2), comp_domain(3):comp_domain(4)))
call get_region_bounds( &
gridname,comp_domain(1),comp_domain(2),comp_domain(3),comp_domain(4),region2,override_array(curr_position)%region2)
endif
endif
! record fieldname, gridname in override_array
override_array(curr_position)%fieldname = fieldname_code
override_array(curr_position)%gridname = gridname
override_array(curr_position)%comp_domain = comp_domain
!4 get index for time interp
if(ongrid) then
id_time = init_external_field(filename,fieldname,domain=domain,verbose=.false.,use_comp_domain=use_comp_domain)
dims = get_external_field_size(id_time)
override_array(curr_position)%dims = dims
if(id_time<0) call mpp_error(FATAL,'data_override:field not found in init_external_field 1')
override_array(curr_position)%t_index = id_time
else !ongrid=false
id_time = init_external_field(filename,fieldname,domain=domain, axis_centers=axis_centers,&
axis_sizes=axis_sizes, verbose=.false.,override=.true.,use_comp_domain=use_comp_domain)
dims = get_external_field_size(id_time)
override_array(curr_position)%dims = dims
if(id_time<0) call mpp_error(FATAL,'data_override:field not found in init_external_field 2')
override_array(curr_position)%t_index = id_time
!5 Get local lon and lat of model grid
select case(gridname)
case('OCN')
lon_local => lon_local_ocn; lat_local => lat_local_ocn
case('ICE')
lon_local => lon_local_ice; lat_local => lat_local_ice
case('ATM')
lon_local => lon_local_atm; lat_local => lat_local_atm
case('LND')
lon_local => lon_local_lnd; lat_local => lat_local_lnd
case default
call mpp_error(FATAL,'error: gridname not recognized in data_override')
end select
!7 get lon and lat of the input (source) grid, assuming that axis%data contains
! lat and lon of the input grid (in degrees)
call get_axis_bounds(axis_centers(1),axis_bounds(1), axis_centers)
call get_axis_bounds(axis_centers(2),axis_bounds(2), axis_centers)
allocate(lon_in(axis_sizes(1)+1), lat_in(axis_sizes(2)+1))
call mpp_get_axis_data(axis_bounds(1),lon_in)
call mpp_get_axis_data(axis_bounds(2),lat_in)
! convert lon_in and lat_in from deg to radian
lon_in = lon_in * deg_to_radian
lat_in = lat_in * deg_to_radian
select case (data_table(index1)%interpol_method)
case ('bilinear')
call horiz_interp_new (override_array(curr_position)%horz_interp,lon_in, lat_in, lon_local, lat_local,&
interp_method="bilinear")
case ('bicubic')
call horiz_interp_new (override_array(curr_position)%horz_interp,lon_in, lat_in, lon_local, lat_local,&
interp_method="bicubic")
end select
deallocate(lon_in)
deallocate(lat_in)
endif !(ongrid)
else !curr_position >0
dims = override_array(curr_position)%dims
comp_domain = override_array(curr_position)%comp_domain
!9 Get id_time previously stored in override_array
id_time = override_array(curr_position)%t_index
endif !if curr_position < 0
allocate(data(comp_domain(1):comp_domain(2),comp_domain(3):comp_domain(4),size(data1,3)))
data = HUGE(1.0)
! Determine if data in netCDF file is 2D or not
data_file_is_2D = .false.
if((dims(3) == 1) .and. (size(data1,3)>1)) data_file_is_2D = .true.
if(ongrid) then
!10 do time interp to get data in compute_domain
if(data_file_is_2D) then
call time_interp_external(id_time,time,data(:,:,1),verbose=.false.)
data(:,:,1) = data(:,:,1)*factor
do i = 2, size(data,3)
data(:,:,i) = data(:,:,1)
enddo
else
call time_interp_external(id_time,time,data,verbose=.false.)
data = data*factor
endif
else ! off grid case
! do time interp to get global data
if(data_file_is_2D) then
call time_interp_external(id_time,time,data(:,:,1),verbose=.false.,horz_interp=override_array(curr_position)%horz_interp)
data(:,:,1) = data(:,:,1)*factor
do i = 2, size(data,3)
data(:,:,i) = data(:,:,1)
enddo
else
call time_interp_external(id_time,time,data,verbose=.false.,horz_interp=override_array(curr_position)%horz_interp)
data = data*factor
endif
endif
if(present(region1)) then
do j = comp_domain(3), comp_domain(4)
jlocal = j - comp_domain(3) + 1
do i = comp_domain(1), comp_domain(2)
if(override_array(curr_position)%region1(i,j)) then
ilocal = i - comp_domain(1) + 1
data1(ilocal,jlocal,:) = data(i,j,:)
endif
enddo
enddo
if(present(region2)) then
do j = comp_domain(3), comp_domain(4)
jlocal = j - comp_domain(3) + 1
do i = comp_domain(1), comp_domain(2)
if(override_array(curr_position)%region2(i,j)) then
ilocal = i - comp_domain(1) + 1
data1(ilocal,jlocal,:) = data(i,j,:)
endif
enddo
enddo
endif
else
data1 = data
endif
if(PRESENT(override)) override = .true.
deallocate(data)
end subroutine data_override_3d
!
!
!
! This routine performs data override for scalar fields
!
! call data_override(fieldname,data,time,override)
!
!
!
! Grid name (Ocean, Ice, Atmosphere, Land)
!
!
! Field name as used in the code (may be different from the name in NetCDF data file)
!
!
! array containing output data
!
!
! model time
!
!
! TRUE if the field is overriden, FALSE otherwise
!
!
!
subroutine data_override_0d(gridname,fieldname_code,data,time,override,data_index)
character(len=3), intent(in) :: gridname ! model grid ID
character(len=*), intent(in) :: fieldname_code ! field name as used in the model
logical, intent(out), optional :: override ! true if the field has been overriden succesfully
type(time_type), intent(in) :: time !(target) model time
real, intent(out) :: data !data returned by this call
integer, intent(in), optional :: data_index
character(len=512) :: filename !file containing source data
character(len=128) :: fieldname ! fieldname used in the data file
integer :: index1 ! field index in data_table
integer :: id_time !index for time interp in override array
integer :: curr_position ! position of the field currently processed in override_array
integer :: i
real :: factor
if(.not.module_is_initialized) &
call mpp_error(FATAL,'Error: need to call data_override_init first')
!1 Look for the data file in data_table
if(PRESENT(override)) override = .false.
if (present(data_index)) then
index1 = data_index
else
index1 = -1
do i = 1, table_size
if( trim(gridname) /= trim(data_table(i)%gridname)) cycle
if( trim(fieldname_code) /= trim(data_table(i)%fieldname_code)) cycle
index1 = i ! field found
exit
enddo
if(index1 .eq. -1) then
if(mpp_pe() == mpp_root_pe() .and. debug_data_override) &
call mpp_error(WARNING,'this field is NOT found in data_table: '//trim(fieldname_code))
return ! NO override was performed
endif
endif
fieldname = data_table(index1)%fieldname_file ! fieldname in netCDF data file
factor = data_table(index1)%factor
if(fieldname == "") then
data = factor
if(PRESENT(override)) override = .true.
return
else
filename = data_table(index1)%file_name
if (filename == "") call mpp_error(FATAL,'data_override: filename not given in data_table')
endif
!3 Check if fieldname has been previously processed
curr_position = -1
if(num_fields > 0 ) then
do i = 1, num_fields
if(trim(override_array(i)%gridname) /= trim(gridname)) cycle
if(trim(override_array(i)%fieldname) /= trim(fieldname_code)) cycle
curr_position = i
exit
enddo
endif
if(curr_position < 0) then ! the field has not been processed previously
num_fields = num_fields + 1
curr_position = num_fields
! record fieldname, gridname in override_array
override_array(curr_position)%fieldname = fieldname_code
override_array(curr_position)%gridname = gridname
id_time = init_external_field(filename,fieldname,verbose=.false.)
if(id_time<0) call mpp_error(FATAL,'data_override:field not found in init_external_field 1')
override_array(curr_position)%t_index = id_time
else !curr_position >0
!9 Get id_time previously stored in override_array
id_time = override_array(curr_position)%t_index
endif !if curr_position < 0
!10 do time interp to get data in compute_domain
call time_interp_external(id_time, time, data, verbose=.false.)
data = data*factor
if(PRESENT(override)) override = .true.
end subroutine data_override_0d
!
!===============================================================================================
! Get lon and lat of three model (target) grids from grid_spec.nc
subroutine get_grid_version_1(grid_file, mod_name, domain, isc, iec, jsc, jec, lon, lat, min_lon, max_lon)
character(len=*), intent(in) :: grid_file
character(len=*), intent(in) :: mod_name
type(domain2d), intent(in) :: domain
integer, intent(in) :: isc, iec, jsc, jec
real, dimension(isc:,jsc:), intent(out) :: lon, lat
real, intent(out) :: min_lon, max_lon
integer :: i, j, siz(4)
integer :: nlon, nlat ! size of global lon and lat
real(r8_kind), dimension(:,:,:), allocatable :: lon_vert, lat_vert !of OCN grid vertices
real(r8_kind), dimension(:), allocatable :: glon, glat ! lon and lat of 1-D grid of atm/lnd
logical :: is_new_grid
integer :: is, ie, js, je
integer :: isd, ied, jsd, jed
integer :: isg, ieg, jsg, jeg
type(domain2d) :: domain2
character(len=3) :: xname, yname
call mpp_get_data_domain(domain, isd, ied, jsd, jed)
call mpp_get_global_domain(domain, isg, ieg, jsg, jeg)
select case(mod_name)
case('ocn', 'ice')
is_new_grid = .FALSE.
if(field_exist(grid_file, 'x_T')) then
is_new_grid = .true.
else if(field_exist(grid_file, 'geolon_t')) then
is_new_grid = .FALSE.
else
call mpp_error(FATAL,'data_override: both x_T and geolon_t is not in the grid file '//trim(grid_file) )
endif
if(is_new_grid) then
call field_size(grid_file, 'x_T', siz)
nlon = siz(1); nlat = siz(2)
call check_grid_sizes(trim(mod_name)//'_domain ', domain, nlon, nlat)
allocate(lon_vert(isc:iec,jsc:jec,4), lat_vert(isc:iec,jsc:jec,4) )
call read_data(trim(grid_file), 'x_vert_T', lon_vert, domain)
call read_data(trim(grid_file), 'y_vert_T', lat_vert, domain)
!2 Global lon and lat of ocean grid cell centers are determined from adjacent vertices
lon(:,:) = (lon_vert(:,:,1) + lon_vert(:,:,2) + lon_vert(:,:,3) + lon_vert(:,:,4))*0.25
lat(:,:) = (lat_vert(:,:,1) + lat_vert(:,:,2) + lat_vert(:,:,3) + lat_vert(:,:,4))*0.25
else
if(grid_center_bug) call mpp_error(NOTE, &
'data_override: grid_center_bug is set to true, the grid center location may be incorrect')
call field_size(grid_file, 'geolon_vert_t', siz)
nlon = siz(1) - 1; nlat = siz(2) - 1;
call check_grid_sizes(trim(mod_name)//'_domain ', domain, nlon, nlat)
call mpp_copy_domain(domain, domain2)
call mpp_set_compute_domain(domain2, isc, iec+1, jsc, jec+1, iec-isc+2, jec-jsc+2 )
call mpp_set_data_domain (domain2, isd, ied+1, jsd, jed+1, ied-isd+2, jed-jsd+2 )
call mpp_set_global_domain (domain2, isg, ieg+1, jsg, jeg+1, ieg-isg+2, jeg-jsg+2 )
allocate(lon_vert(isc:iec+1,jsc:jec+1,1))
allocate(lat_vert(isc:iec+1,jsc:jec+1,1))
call read_data(trim(grid_file), 'geolon_vert_t', lon_vert, domain2)
call read_data(trim(grid_file), 'geolat_vert_t', lat_vert, domain2)
if(grid_center_bug) then
do j = jsc, jec
do i = isc, iec
lon(i,j) = (lon_vert(i,j,1) + lon_vert(i+1,j,1))/2.
lat(i,j) = (lat_vert(i,j,1) + lat_vert(i,j+1,1))/2.
enddo
enddo
else
do j = jsc, jec
do i = isc, iec
lon(i,j) = (lon_vert(i,j,1) + lon_vert(i+1,j,1) + &
lon_vert(i+1,j+1,1) + lon_vert(i,j+1,1))*0.25
lat(i,j) = (lat_vert(i,j,1) + lat_vert(i+1,j,1) + &
lat_vert(i+1,j+1,1) + lat_vert(i,j+1,1))*0.25
enddo
enddo
end if
call mpp_deallocate_domain(domain2)
endif
deallocate(lon_vert)
deallocate(lat_vert)
case('atm', 'lnd')
if(trim(mod_name) == 'atm') then
xname = 'xta'; yname = 'yta'
else
xname = 'xtl'; yname = 'ytl'
endif
call field_size(grid_file, xname, siz)
nlon = siz(1); allocate(glon(nlon))
call read_data(grid_file, xname, glon)
call field_size(grid_file, yname, siz)
nlat = siz(1); allocate(glat(nlat))
call read_data(grid_file, yname, glat)
call check_grid_sizes(trim(mod_name)//'_domain ', domain, nlon, nlat)
is = isc - isg + 1; ie = iec - isg + 1
js = jsc - jsg + 1; je = jec - jsg + 1
do j = js, jec
do i = is, ie
lon(i,j) = glon(i)
lat(i,j) = glat(j)
enddo
enddo
deallocate(glon)
deallocate(glat)
case default
call mpp_error(FATAL, "data_override_mod: mod_name should be 'atm', 'ocn', 'ice' or 'lnd' ")
end select
! convert from degree to radian
lon = lon * deg_to_radian
lat = lat* deg_to_radian
min_lon = minval(lon)
max_lon = maxval(lon)
call mpp_min(min_lon)
call mpp_max(max_lon)
end subroutine get_grid_version_1
! Get global lon and lat of three model (target) grids from mosaic.nc
! z1l: currently we assume the refinement ratio is 2 and there is one tile on each pe.
subroutine get_grid_version_2(mosaic_file, mod_name, domain, isc, iec, jsc, jec, lon, lat, min_lon, max_lon)
character(len=*), intent(in) :: mosaic_file
character(len=*), intent(in) :: mod_name
type(domain2d), intent(in) :: domain
integer, intent(in) :: isc, iec, jsc, jec
real, dimension(isc:,jsc:), intent(out) :: lon, lat
real, intent(out) :: min_lon, max_lon
integer :: i, j, siz(4)
integer :: nlon, nlat ! size of global grid
integer :: nlon_super, nlat_super ! size of global supergrid.
integer :: isd, ied, jsd, jed
integer :: isg, ieg, jsg, jeg
integer :: isc2, iec2, jsc2, jec2
character(len=256) :: solo_mosaic_file, grid_file
real, allocatable :: tmpx(:,:), tmpy(:,:)
type(domain2d) :: domain2
if(trim(mod_name) .NE. 'atm' .AND. trim(mod_name) .NE. 'ocn' .AND. &
trim(mod_name) .NE. 'ice' .AND. trim(mod_name) .NE. 'lnd' ) call mpp_error(FATAL, &
"data_override_mod: mod_name should be 'atm', 'ocn', 'ice' or 'lnd' ")
call mpp_get_data_domain(domain, isd, ied, jsd, jed)
call mpp_get_global_domain(domain, isg, ieg, jsg, jeg)
! get the grid file to read
if(field_exist(mosaic_file, trim(mod_name)//'_mosaic_file' )) then
call read_data(mosaic_file, trim(mod_name)//'_mosaic_file', solo_mosaic_file)
solo_mosaic_file = 'INPUT/'//trim(solo_mosaic_file)
else
solo_mosaic_file = mosaic_file
end if
call get_mosaic_tile_grid(grid_file, solo_mosaic_file, domain)
call field_size(grid_file, 'area', siz)
nlon_super = siz(1); nlat_super = siz(2)
if( mod(nlon_super,2) .NE. 0) call mpp_error(FATAL, &
'data_override_mod: '//trim(mod_name)//' supergrid longitude size can not be divided by 2')
if( mod(nlat_super,2) .NE. 0) call mpp_error(FATAL, &
'data_override_mod: '//trim(mod_name)//' supergrid latitude size can not be divided by 2')
nlon = nlon_super/2;
nlat = nlat_super/2;
call check_grid_sizes(trim(mod_name)//'_domain ', domain, nlon, nlat)
!--- setup the domain for super grid.
call mpp_copy_domain(domain, domain2)
call mpp_set_compute_domain(domain2, 2*isc-1, 2*iec+1, 2*jsc-1, 2*jec+1, 2*iec-2*isc+3, 2*jec-2*jsc+3 )
call mpp_set_data_domain (domain2, 2*isd-1, 2*ied+1, 2*jsd-1, 2*jed+1, 2*ied-2*isd+3, 2*jed-2*jsd+3 )
call mpp_set_global_domain (domain2, 2*isg-1, 2*ieg+1, 2*jsg-1, 2*jeg+1, 2*ieg-2*isg+3, 2*jeg-2*jsg+3 )
call mpp_get_compute_domain(domain2, isc2, iec2, jsc2, jec2)
if(isc2 .NE. 2*isc-1 .OR. iec2 .NE. 2*iec+1 .OR. jsc2 .NE. 2*jsc-1 .OR. jec2 .NE. 2*jec+1) then
call mpp_error(FATAL, 'data_override_mod: '//trim(mod_name)//' supergrid domain is not set properly')
endif
allocate(tmpx(isc2:iec2, jsc2:jec2), tmpy(isc2:iec2, jsc2:jec2) )
call read_data( grid_file, 'x', tmpx, domain2)
call read_data( grid_file, 'y', tmpy, domain2)
! copy data onto model grid
if(trim(mod_name) == 'ocn' .OR. trim(mod_name) == 'ice') then
do j = jsc, jec
do i = isc, iec
lon(i,j) = (tmpx(i*2-1,j*2-1)+tmpx(i*2+1,j*2-1)+tmpx(i*2+1,j*2+1)+tmpx(i*2-1,j*2+1))*0.25
lat(i,j) = (tmpy(i*2-1,j*2-1)+tmpy(i*2+1,j*2-1)+tmpy(i*2+1,j*2+1)+tmpy(i*2-1,j*2+1))*0.25
end do
end do
else
do j = jsc, jec
do i = isc, iec
lon(i,j) = tmpx(i*2,j*2)
lat(i,j) = tmpy(i*2,j*2)
end do
end do
endif
! convert to radian
lon = lon * deg_to_radian
lat = lat * deg_to_radian
deallocate(tmpx, tmpy)
min_lon = minval(lon)
max_lon = maxval(lon)
call mpp_min(min_lon)
call mpp_max(max_lon)
call mpp_deallocate_domain(domain2)
end subroutine get_grid_version_2
!===============================================================================================
subroutine get_region_bounds(gridname, is,ie,js,je, region_in, region_out)
! Given gridname and region limits (in lat and lon), this routine returns
! the region's indices (in i and j) determined on global array
! lat values are between (-90, +90), lon values:(0,360)
! Do not give negative lon
character(len=3), intent(in) :: gridname ! model grid ID
integer, intent(in) :: is,ie,js,je ! comp domain index limits in global space
real, intent(in) :: region_in(4) !(lat_start, lat_end, lon_start, lon_end)
logical, intent(out), dimension(is:ie,js:je) :: region_out
real, dimension(:,:), pointer :: lon_local, lat_local
integer :: i,j
real :: lat_start, lat_end, lon_start, lon_end
real :: max_glo_lon, min_glo_lon
character(len=256) :: error_message
lat_start = region_in(1)
lat_end = region_in(2)
lon_start = region_in(3)
lon_end = region_in(4)
if(lat_start < -90. .or. lat_end > 90.) then
error_message = 'data_override: latitude out of range -90 to +90 lat_start= lat_end= '
write(error_message(60:67), '(f8.2)') lat_start
write(error_message(78:85), '(f8.2)') lat_end
call mpp_error(FATAL,trim(error_message))
endif
if(lat_start > lat_end) then
error_message = 'data_override: lat_start greater than lat_end. lon_start= lon_end= '
write(error_message(58:65), '(f8.2)') lat_start
write(error_message(76:83), '(f8.2)') lat_end
call mpp_error(FATAL,trim(error_message))
endif
lat_start = lat_start * deg_to_radian
lat_end = lat_end * deg_to_radian
lon_start = lon_start * deg_to_radian
lon_end = lon_end * deg_to_radian
select case(gridname)
case('OCN')
lon_local => lon_local_ocn
lat_local => lat_local_ocn
max_glo_lon = max_glo_lon_ocn
min_glo_lon = min_glo_lon_ocn
case('ICE')
lon_local => lon_local_ocn
lat_local => lat_local_ocn
max_glo_lon = max_glo_lon_ice
min_glo_lon = min_glo_lon_ice
case('ATM')
lon_local => lon_local_atm
lat_local => lat_local_atm
max_glo_lon = max_glo_lon_atm
min_glo_lon = min_glo_lon_atm
case('LND')
lon_local => lon_local_lnd
lat_local => lat_local_lnd
max_glo_lon = max_glo_lon_lnd
min_glo_lon = min_glo_lon_lnd
case default
call mpp_error(FATAL,'data_override: grid not recognized. Grid name='//gridname)
end select
! Adjust lon_start and lon_end.
! Because longitude is cyclic, the longitude of the grid points could be anything,
! except for the constraint that maxval(lon_global) - minval(lon_global) < 2*PI
! We want to be able to be specify lon_start and lon_end independently of the grid values.
! e.g. If lon_end=270 deg but the grid goes from -180 to +180 then we want to adjust lon_end to -90
! To accomplish this:
! lon_start is adjusted such that lon_start > maxval(lon_global) - 2*PI
! lon_end is adjusted such that lon_end < minval(lon_global) + 2*PI
lon_start = lon_start + (ceiling((max_glo_lon-lon_start)/tpi) - 1)*tpi
lon_end = lon_end + (floor ((min_glo_lon-lon_end )/tpi) + 1)*tpi
do j=js,je
do i=is,ie
region_out(i,j) = (lat_local(i,j) > lat_start .and. lat_local(i,j) < lat_end)
if(lon_end >= lon_start) then
region_out(i,j) = region_out(i,j) .and. (lon_local(i,j) < lon_end .and. lon_local(i,j) > lon_start)
else
region_out(i,j) = region_out(i,j) .and. (lon_local(i,j) < lon_end .or. lon_local(i,j) > lon_start)
endif
enddo
enddo
end subroutine get_region_bounds
!===============================================================================================
end module data_override_mod
#ifdef test_data_override
program test
! Input data and path_names file for this program is in:
! /archive/pjp/unit_tests/test_data_override/lima/exp1
use mpp_domains_mod, only: domain2d, mpp_define_domains, mpp_get_compute_domain, mpp_define_layout
use fms_mod, only: fms_init, fms_end, mpp_npes, file_exist, open_namelist_file, check_nml_error, close_file
use fms_mod, only: error_mesg, FATAL, file_exist, field_exist, field_size
use fms_io_mod, only: read_data, fms_io_exit
use constants_mod, only: constants_init, pi
use time_manager_mod, only: time_type, set_calendar_type, set_date, NOLEAP, JULIAN, operator(+), set_time, print_time
use diag_manager_mod, only: diag_manager_init, diag_manager_end, register_static_field, register_diag_field
use diag_manager_mod, only: send_data, diag_axis_init
use data_override_mod, only: data_override_init, data_override
implicit none
type(domain2d) :: Domain
integer :: nlon, nlat, siz(4)
real, allocatable, dimension(:) :: x, y
real, allocatable, dimension(:,:) :: lon, lat
real, allocatable, dimension(:,:) :: sst, ice
integer :: id_x, id_y, id_lon, id_lat, id_sst, id_ice
integer :: i, j, is, ie, js, je, unit, io, ierr
real :: rad_to_deg
character(len=36) :: message
type(time_type) :: Time
logical :: used, ov_sst, ov_ice
integer, dimension(2) :: layout = (/0,0/)
character(len=256) :: solo_mosaic_file, tile_file
character(len=128) :: grid_file = "INPUT/grid_spec.nc"
namelist / test_data_override_nml / layout
call fms_init
call constants_init
call set_calendar_type(NOLEAP)
call diag_manager_init
rad_to_deg = 180./pi
if (file_exist('input.nml')) then
unit = open_namelist_file ( )
ierr=1
do while (ierr /= 0)
read(unit, nml=test_data_override_nml, iostat=io, end=10)
ierr = check_nml_error(io, 'test_data_override_nml')
enddo
10 call close_file (unit)
endif
if(field_exist(grid_file, "x_T" ) ) then
call field_size(grid_file, 'x_T', siz)
nlon = siz(1)
nlat = siz(2)
else if(field_exist(grid_file, "geolon_t" ) ) then
call field_size(grid_file, 'geolon_t', siz)
nlon = siz(1)
nlat = siz(2)
else if (field_exist(grid_file, "ocn_mosaic_file" )) then
call read_data(grid_file, 'ocn_mosaic_file', solo_mosaic_file)
solo_mosaic_file = 'INPUT/'//trim(solo_mosaic_file)
call field_size(solo_mosaic_file, 'gridfiles', siz)
if( siz(2) .NE. 1) call error_mesg('test_data_override', 'only support single tile mosaic, contact developer', FATAL)
call read_data(solo_mosaic_file, 'gridfiles', tile_file)
tile_file = 'INPUT/'//trim(tile_file)
call field_size(tile_file, 'area', siz)
if(mod(siz(1),2) .NE. 0 .OR. mod(siz(2),2) .NE. 0 ) call error_mesg('test_data_override', &
"test_data_override: supergrid size can not be divided by 2", FATAL)
nlon = siz(1)/2
nlat = siz(2)/2
else
call error_mesg('test_data_override', 'x_T, geolon_t and ocn_mosaic_file does not exist', FATAL)
end if
if(layout(1)*layout(2) .NE. mpp_npes() ) then
call mpp_define_layout( (/1,nlon,1,nlat/), mpp_npes(), layout )
end if
call mpp_define_domains( (/1,nlon,1,nlat/), layout, Domain, name='test_data_override')
call data_override_init(Ice_domain_in=Domain, Ocean_domain_in=Domain)
call mpp_get_compute_domain(Domain, is, ie, js, je)
call get_grid
allocate(x(nlon), y(nlat))
do i=1,nlon
x(i) = i
enddo
do j=1,nlat
y(j) = j
enddo
Time = set_date(2,1,1,0,0,0)
allocate(sst(is:ie,js:je), ice(is:ie,js:je))
id_x = diag_axis_init('x', x, 'point_E', 'x', long_name='point_E', Domain2=Domain)
id_y = diag_axis_init('y', y, 'point_N', 'y', long_name='point_N', Domain2=Domain)
Time = Time + set_time(0,1)
id_lon = register_static_field('test_data_override_mod', 'lon', (/id_x,id_y/), 'longitude', 'Degrees')
id_lat = register_static_field('test_data_override_mod', 'lat', (/id_x,id_y/), 'longitude', 'Degrees')
id_sst = register_diag_field ('test_data_override_mod', 'sst', (/id_x,id_y/), Time, 'SST', 'K')
id_ice = register_diag_field ('test_data_override_mod', 'ice', (/id_x,id_y/), Time, 'ICE', ' ')
used = send_data(id_lon, lon, Time)
used = send_data(id_lat, lat, Time)
sst = 0.
ice = 0.
!call data_override('OCN','sst_obs',sst,Time,override=ov_sst, region1=(/-45., 45.,-190., -10./)) ! lima crashes. lima_pjp works
!call data_override('OCN','sst_obs',sst,Time,override=ov_sst, region1=(/-45., 45., 90., 270./)) ! lima crashes with error message. lima_pjp works
!call data_override('OCN','sst_obs',sst,Time,override=ov_sst, region1=(/-45., 45., -10.,-190./)) ! lima does no override. lima_pjp works
!call data_override('OCN','sst_obs',sst,Time,override=ov_sst, region1=(/ 65., 90.,-190., -10./)) ! lima crashes with error message. lima_pjp works
call data_override('OCN','sst_obs',sst,Time,override=ov_sst, region1=(/ 72., 90.,-230., 30./)) ! lima not tested. lima_pjp works
!call data_override('OCN','sst_obs',sst,Time,override=ov_sst, region1=(/-45., 45.,-190., -10./))
!call data_override('OCN','sst_obs',sst,Time,override=ov_sst)
call data_override('ICE', 'sic_obs', ice, Time, override=ov_ice)
if(.not.ov_sst .or. .not.ov_ice) then
if(ov_sst) then
message = 'override failed for ice'
else if(ov_ice) then
message = 'override failed for sst'
else
message = 'override failed for both sst and ice'
endif
call error_mesg('test_data_override', trim(message), FATAL)
endif
if(id_sst > 0) used = send_data(id_sst, sst, Time)
if(id_ice > 0) used = send_data(id_ice, ice, Time)
!-------------------------------------------------------------------------------------------------------
! All the tests above are tests of regional override.
! What follows is a test of calendar conversion
!Time = set_date(1980,2,27,0,0,0)
!call print_time(Time)
!call data_override('OCN','sst_obs',sst,Time)
!if(id_sst > 0) used = send_data(id_sst, sst, Time)
!Time = set_date(1980,2,28,0,0,0)
!call print_time(Time)
!call data_override('OCN','sst_obs',sst,Time)
!if(id_sst > 0) used = send_data(id_sst, sst, Time)
!Time = set_date(1980,2,29,0,0,0)
!call print_time(Time)
!call data_override('OCN','sst_obs',sst,Time)
!if(id_sst > 0) used = send_data(id_sst, sst, Time)
!Time = set_date(1980,3,1,0,0,0)
!call print_time(Time)
!call data_override('OCN','sst_obs',sst,Time)
!if(id_sst > 0) used = send_data(id_sst, sst, Time)
!Time = set_date(1980,3,2,0,0,0)
!call print_time(Time)
!call data_override('OCN','sst_obs',sst,Time)
!if(id_sst > 0) used = send_data(id_sst, sst, Time)
!-------------------------------------------------------------------------------------------------------
call diag_manager_end(Time)
call fms_io_exit
call fms_end
contains
!=================================================================================================================================
subroutine get_grid
real, allocatable, dimension(:,:,:) :: lon_vert_glo, lat_vert_glo
real, allocatable, dimension(:,:) :: lon_global, lat_global
integer, dimension(4) :: siz
character(len=128) :: message
if(field_exist(grid_file, 'x_T')) then
call field_size(grid_file, 'x_T', siz)
if(siz(1) /= nlon .or. siz(2) /= nlat) then
write(message,'(a,2i4)') 'x_T is wrong shape. shape(x_T)=',siz(1:2)
call error_mesg('test_data_override', trim(message), FATAL)
endif
allocate(lon_vert_glo(nlon,nlat,4), lat_vert_glo(nlon,nlat,4) )
allocate(lon_global (nlon,nlat ), lat_global (nlon,nlat ) )
call read_data(trim(grid_file), 'x_vert_T', lon_vert_glo, no_domain=.true.)
call read_data(trim(grid_file), 'y_vert_T', lat_vert_glo, no_domain=.true.)
lon_global(:,:) = (lon_vert_glo(:,:,1) + lon_vert_glo(:,:,2) + lon_vert_glo(:,:,3) + lon_vert_glo(:,:,4))*0.25
lat_global(:,:) = (lat_vert_glo(:,:,1) + lat_vert_glo(:,:,2) + lat_vert_glo(:,:,3) + lat_vert_glo(:,:,4))*0.25
else if(field_exist(grid_file, "geolon_t" ) ) then
call field_size(grid_file, 'geolon_vert_t', siz)
if(siz(1) /= nlon+1 .or. siz(2) /= nlat+1) then
write(message,'(a,2i4)') 'geolon_vert_t is wrong shape. shape(geolon_vert_t)=',siz(1:2)
call error_mesg('test_data_override', trim(message), FATAL)
endif
allocate(lon_vert_glo(nlon+1,nlat+1,1), lat_vert_glo(nlon+1,nlat+1,1))
allocate(lon_global (nlon, nlat ), lat_global (nlon, nlat ))
call read_data(trim(grid_file), 'geolon_vert_t', lon_vert_glo, no_domain=.true.)
call read_data(trim(grid_file), 'geolat_vert_t', lat_vert_glo, no_domain=.true.)
do i = 1, nlon
do j = 1, nlat
lon_global(i,j) = (lon_vert_glo(i,j,1) + lon_vert_glo(i+1,j,1) + &
lon_vert_glo(i+1,j+1,1) + lon_vert_glo(i,j+1,1))*0.25
lat_global(i,j) = (lat_vert_glo(i,j,1) + lat_vert_glo(i+1,j,1) + &
lat_vert_glo(i+1,j+1,1) + lat_vert_glo(i,j+1,1))*0.25
enddo
enddo
else if( field_exist(grid_file, "ocn_mosaic_file") ) then ! reading from mosaic file
call field_size(tile_file, 'area', siz)
if(siz(1) /= nlon*2 .or. siz(2) /= nlat*2) then
write(message,'(a,2i4)') 'area is wrong shape. shape(area)=',siz(1:2)
call error_mesg('test_data_override', trim(message), FATAL)
endif
allocate(lon_vert_glo(siz(1)+1,siz(2)+1,1), lat_vert_glo(siz(1)+1,siz(2)+1,1))
allocate(lon_global (nlon, nlat ), lat_global (nlon, nlat ))
call read_data( tile_file, 'x', lon_vert_glo, no_domain=.true.)
call read_data( tile_file, 'y', lat_vert_glo, no_domain=.true.)
do j = 1, nlat
do i = 1, nlon
lon_global(i,j) = lon_vert_glo(i*2,j*2,1)
lat_global(i,j) = lat_vert_glo(i*2,j*2,1)
end do
end do
end if
allocate(lon(is:ie,js:je), lat(is:ie,js:je))
lon = lon_global(is:ie,js:je)
lat = lat_global(is:ie,js:je)
deallocate(lon_vert_glo)
deallocate(lat_vert_glo)
deallocate(lon_global)
deallocate(lat_global)
end subroutine get_grid
!=================================================================================================================================
end program test
#endif