!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !! 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 !! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! program river_regrid !----------------------------------------------------------------------- ! GNU General Public License ! ! This program 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; either version 2 of ! the License, or (at your option) any later version. ! ! MOM 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. ! ! For the full text of the GNU General Public License, ! write to: Free Software Foundation, Inc., ! 675 Mass Ave, Cambridge, MA 02139, USA. ! or see: http://www.gnu.org/licenses/gpl.html !----------------------------------------------------------------------- ! ! Zhi Liang ! Kirsten Findell ! ! This program can remap river network data from spherical grid onto another ! spherical grid. ! ! ! The program expects to read river network data from a netcdf file, which ! is specified by the namelist variable "river_input_file". This file should ! contains field 'cellarea', 'tocell', 'fromcell', 'basin', 'basincells', ! 'order', 'travel', 'subL', 'subA','disttomouth', 'disttoocean' and 'dx'. ! The program will remap the data in "river_input_file" onto the grid, which ! is specified by namelist grid_file. The grid file should contains the same ! grid as the land modle to be run. The output is stored in a netcdf file, which ! is specified by river_output_file. ! use mpp_mod, only : mpp_error, FATAL, NOTE, mpp_init, mpp_pe, mpp_root_pe, mpp_npes use mpp_domains_mod, only : domain2D, mpp_define_layout, mpp_define_domains, mpp_get_compute_domain use mpp_domains_mod, only : mpp_global_field use mpp_io_mod, only : mpp_open, mpp_close, axistype, fieldtype, mpp_write, mpp_write_meta use mpp_io_mod, only : MPP_OVERWR, MPP_NETCDF, MPP_MULTI, MPP_RDONLY, MPP_ASCII, MPP_SINGLE use mpp_io_mod, only : mpp_get_atts, mpp_get_axes, mpp_get_axis_data, mpp_get_fields use mpp_io_mod, only : mpp_read, mpp_get_info, mpp_io_init use fms_mod, only : open_namelist_file, check_nml_error, stdout, stdlog, close_file use fms_mod, only : file_exist, write_version_number, error_mesg, read_data use fms_mod, only : fms_init, fms_end, field_exist, field_size use axis_utils_mod, only : get_axis_cart, get_axis_bounds use constants_mod, only : PI, radius, constants_init, DEG_TO_RAD use fms_io_mod, only : fms_io_exit use horiz_interp_mod, only : horiz_interp_init, horiz_interp_new, horiz_interp, horiz_interp_del, horiz_interp_type implicit none !--- namelist interface ---------------------------------------------- ! ! ! river data source file. ! ! ! the grid file that contains land and ocean grid information. ! ! ! The output river data file after coupled with land grid. ! ! ! starting and ending longitude of the river network to be extended to. Default value is 0 and 360. ! ! ! starting and ending latitude of the river network to be extended to. Default value is -90 and 90. ! ! ! The ending latitude. Default value is 90. Used to extend river network. ! ! character(len=128) :: river_input_file = 'river_input.nc' character(len=128) :: grid_file = 'grid_spec.nc' character(len=128) :: river_output_file = 'river_output.nc' ! character(len=128) :: edit_table = 'river_table' real :: lon_start = 0 real :: lon_end = 360 real :: lat_start = -90 real :: lat_end = 90 namelist /river_regrid_nml/ river_input_file, river_output_file, grid_file, & lon_start, lon_end, lat_start, lat_end real :: missing_value = -9999. !--- derived data type ------------------------------------------------ type river_regrid_type real, dimension(:), pointer :: lon => NULL() ! longitude (in degree) real, dimension(:), pointer :: lat => NULL() ! lattitude (in degree) real, dimension(:), pointer :: lonb => NULL() ! longitude edges (in degree) real, dimension(:), pointer :: latb => NULL() ! latitude edges (in degree) real, dimension(:,:), pointer :: slope => NULL() ! slope real, dimension(:,:), pointer :: cellarea => NULL() ! cell area real, dimension(:,:), pointer :: subL => NULL() ! subbasin length real, dimension(:,:), pointer :: subA => NULL() ! subbasin area real, dimension(:,:), pointer :: disttoocean => NULL() ! distant to ocean real, dimension(:,:), pointer :: celllength => NULL() ! cell size integer, dimension(:,:), pointer :: order => NULL() ! river order integer, dimension(:,:), pointer :: basinid => NULL() ! basin id integer, dimension(:,:), pointer :: tocell => NULL() ! tocell information integer, dimension(:,:), pointer :: fromcell => NULL() ! fromcell information integer, dimension(:,:), pointer :: basincells => NULL() ! basincells integer, dimension(:,:), pointer :: travel => NULL() ! number of travel to ocean real, dimension(:,:), pointer :: mask => NULL() ! land/sea mask(land=1) real, dimension(:,:,:), pointer :: dist => NULL() ! distance to neighbor cell integer, dimension(:,:), pointer :: neighbor => NULL() ! neighbor information integer, dimension(:,:), pointer :: land_order => NULL() ! land_order integer :: nlon, nlat ! grid size end type river_regrid_type !--- version information --------------------------------------------- character(len=128) :: version = '$ID$' character(len=128) :: tagname = '$Name: mom4p1_pubrel_dec2009_nnz $' !--- other variables type(river_regrid_type),save :: Source type(river_regrid_type),save :: River real, parameter :: lnd_thresh = 1.0e-6 ! some small number logical :: module_is_initialized = .FALSE. integer :: next_basinid = 0 real :: D2R integer :: nlon, nlat ! grid size of extended river grid real, dimension(:,:), allocatable :: mask_ocn, lon_ocn, lat_ocn !--- begin the program call fms_init call constants_init call river_regrid_init() write(stdout(),*)"complete river_regrid_init" call river_regrid_data(River) write(stdout(),*)"complete river_regrid_data" if(mpp_pe() == mpp_root_pe())call write_river_regrid_data(River) write(stdout(),*)"complete write_river_regrid_data" call river_regrid_end(River) write(stdout(),*)" ****** congradulation! You have successfully run river_regrid" call fms_end contains !--- initialization routine, reading namelist, read river source !--- data and land grid information. subroutine river_regrid_init integer :: unit, ierr, io_status !--- read namelist and write out namelist -------------------------- unit = open_namelist_file() read (unit, river_regrid_nml,iostat=io_status) write (stdout(),'(/)') write (stdout(), river_regrid_nml) write (stdlog(), river_regrid_nml) ierr = check_nml_error(io_status,'river_regrid_nml') call close_file (unit) D2R = PI/180.0 !--- write out version information --------------------------------- call write_version_number( version, tagname ) !--- read the river data from river_input_file call read_river_src_data( ) return end subroutine river_regrid_init !##################################################################### !--- remap and define river routing network. subroutine river_regrid_data(River) type(river_regrid_type), intent(inout) :: River !--- define River to make land and river has the same range and initialize !--- the river data. call define_new_grid(River) !--- the following will be done only on root pe. if(mpp_pe() .NE. mpp_root_pe()) return !--- remove previously land point call trim_river(River) !--- define land order for new river grid call define_new_land_order(River) !--- define new land point data call define_new_land_data(River) !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. call update_coast_land(River) !--- check river data to see if there is any bad value. call check_river_data(River) end subroutine river_regrid_data !#################################################################### subroutine update_coast_land(River) type(river_regrid_type), intent(inout) :: River integer :: nbasin, basin, cur_basin, num_nbrs integer :: i_array(8), j_array(8) integer :: i, j, ii, jj, i_nbr, j_nbr integer :: num_river_merged = 0 integer :: num_river_extended = 0 integer :: num_partial_land = 0 !--- first add one ocean point to the river network with the coast point is a full land cell. !--- ( point with travel=0, tocell > 0) nbasin = maxval(River%basinid) do basin = 1, nbasin LOOP: do j = 1, nlat do i = 1, nlon if(River%basinid(i,j) == basin .AND. River%travel(i,j) == 0) then if(River%tocell(i,j)>0 .AND. River%mask(i,j) ==1 ) then ! full land coast point, not inland point, add one more point. call get_nbr_index(River%tocell(i,j), i, j, i_array, j_array, num_nbrs) if(num_nbrs .ne. 1) call mpp_error(FATAL,'River will flow to one and only one direction') i_nbr = i_array(1) j_nbr = j_array(1) if(River%basinid(i_nbr,j_nbr) >0) then ! the ocean point is already extended. num_river_merged = num_river_merged + 1 cur_basin = River%basinid(i_nbr,j_nbr) if(River%fromcell(i_nbr,j_nbr) <0) then ! write(stdout(), *)"The river with basinid = ", basin, & ! " will be merged into river with basin =", cur_basin call mpp_error(FATAL,'crash') end if do jj = 1, nlat do ii = 1, nlon if(River%basinid(ii,jj) == basin) then River%basinid(ii,jj) = cur_basin River%travel(ii,jj) = River%travel(ii,jj) + 1 end if end do end do if(River%tocell(i,j) .lt. 16) then River%fromcell(i_nbr,j_nbr) = River%fromcell(i_nbr,j_nbr) + River%tocell(i,j)*16 else if(River%tocell(i,j) .ge. 16) then River%fromcell(i_nbr,j_nbr) = River%fromcell(i_nbr,j_nbr) + River%tocell(i,j)/16 endif else num_river_extended = num_river_extended + 1 ! write(stdout(), *) "The river with basinid = ", basin, " will be extended " do jj = 1, nlat do ii = 1, nlon if(River%basinid(ii,jj) == basin) then River%travel(ii,jj) = River%travel(ii,jj) + 1 end if end do end do River%basinid(i_nbr,j_nbr) = basin River%travel(i_nbr,j_nbr) = 0 River%tocell(i_nbr,j_nbr) = 0 if(River%tocell(i,j) .lt. 16) then River%fromcell(i_nbr,j_nbr) = River%tocell(i,j)*16 else if(River%tocell(i,j) .ge. 16) then River%fromcell(i_nbr,j_nbr) = River%tocell(i,j)/16 endif end if end if exit LOOP end if end do end do LOOP end do !--- set tocell of coast partial land to 0 num_partial_land = 0 do j = 1, nlat do i = 1, nlon if(River%travel(i,j) == 0 .AND. River%tocell(i,j) > 0) then ! coast point if(River%mask(i,j) < 1) then River%tocell(i,j) = 0 ! partial land coast point will flow into itself. num_partial_land = num_partial_land + 1 end if end if end do end do write(stdout(),*) "******* number of river extended is :", num_river_extended write(stdout(),*) "******* number of river merged is :", num_river_merged write(stdout(),*) "******* number of coast partial river point with tocell set to 0 is :", num_partial_land end subroutine update_coast_land !#################################################################### subroutine check_river_data(River) type(river_regrid_type), intent(in) :: River integer :: nbasin, basin, ncoast, i, j integer :: i_array(8), j_array(8), i_nbr, j_nbr, num_nbrs ! check that all the data should be missing value or greater than or equal to 0 do j = 1, nlat do i = 1, nlon if(River%basinid(i,j) < 0 .AND. River%basinid(i,j) .NE. missing_value) call mpp_error(FATAL, & "the basinid of some points is less than 0 and not equal to missing_value") if(River%cellarea(i,j) < 0 .AND. River%cellarea(i,j) .NE. missing_value) call mpp_error(FATAL, & "the cellarea of some points is less than 0 and not equal to missing_value") if(River%subL(i,j) < 0 .AND. River%subL(i,j) .NE. missing_value) call mpp_error(FATAL, & "the subL of some points is less than 0 and not equal to missing_value") if(River%subA(i,j) < 0 .AND. River%subA(i,j) .NE. missing_value) call mpp_error(FATAL, & "the subA of some points is less than 0 and not equal to missing_value") if(River%disttoocean(i,j) < 0 .AND. River%disttoocean(i,j) .NE. missing_value) call mpp_error(FATAL, & "the disttoocean of some points is less than 0 and not equal to missing_value") if(River%celllength(i,j) < 0 .AND. River%celllength(i,j) .NE. missing_value) call mpp_error(FATAL, & "the celllength of some points is less than 0 and not equal to missing_value") if(River%order(i,j) < 0 .AND. River%order(i,j) .NE. missing_value) call mpp_error(FATAL, & "the order of some points is less than 0 and not equal to missing_value") if(River%tocell(i,j) < 0 .AND. River%tocell(i,j) .NE. missing_value) call mpp_error(FATAL, & "the tocell of some points is less than 0 and not equal to missing_value") if(River%fromcell(i,j) < 0 .AND. River%fromcell(i,j) .NE. missing_value) call mpp_error(FATAL, & "the fromcell of some points is less than 0 and not equal to missing_value") if(River%basincells(i,j) < 0 .AND. River%basincells(i,j) .NE. missing_value) call mpp_error(FATAL, & "the basincells of some points is less than 0 and not equal to missing_value") if(River%travel(i,j) < 0 .AND. River%travel(i,j) .NE. missing_value) call mpp_error(FATAL, & "the basinid of some points is less than 0 and not equal to missing_value") end do end do ! check river travel to make sure there is one and only one point with travel = 0. nbasin = maxval(River%basinid) do basin = 1, nbasin ncoast = 0 do j = 1, nlat do i = 1, nlon if(River%basinid(i,j) == basin ) then if(River%travel(i,j) == 0 ) ncoast = ncoast + 1 end if end do end do if( ncoast < 0 ) then write(stdout(),*) ' river with basin = ', basin, ' has no point with traver = 0' call mpp_error(FATAL,"some river has no point with travel = 0") end if if( ncoast > 1 ) then write(stdout(),*) ' river with basin = ', basin, ' has more that 1 point with traver = 0' call mpp_error(FATAL,"some river has more than one point with travel = 0") end if end do !--- make sure when the mask is 1 ( land/river), basin is not missing value !--- and = missing_value when mask is 0 ( ocean ) do j = 1, nlat do i = 1, nlon if(River%mask(i,j) > lnd_thresh ) then ! river point if(River%basinid(i,j) == missing_value ) then write(stdout(),*) 'at (i,j) = (', i, ',',j, & '), mask = 1(river), but basinid equal to missing value' call mpp_error(FATAL,"some river point has basinid = missing value") end if else if(River%basinid(i,j) > 0) then if(River%travel(i,j) .NE. 0 .OR. River%tocell(i,j) .NE. 0 ) then write(stdout(),*) 'at (i,j) = (', i, ',',j, & '), mask = 0( ocean), basinid = ', River%basinid(i,j), & ', travel = ', River%travel(i,j), ', tocell = ', River%tocell(i,j) call mpp_error(FATAL,"some ocean point in the river network has nonzero travel or nonzero tocell") end if end if end do end do !--- check travel, tocell, fromcell and basinid do j = 1, nlat do i = 1, nlon if(River%tocell(i,j) >0 ) then ! river point call get_nbr_index(River%tocell(i,j), i, j, i_array, j_array, num_nbrs) if(num_nbrs .ne. 1) then write(stdout(),*) 'at (i,j) = (', i, ',',j, & ', there are ', num_nbrs, ' tocell and the neighbors are: i_nbr = ', & i_array(1:num_nbrs), ', j_nbr = ', j_array(1:num_nbrs) call mpp_error(FATAL,'River can only flow to one direction') end if i_nbr = i_array(1) j_nbr = j_array(1) if(River%basinid(i,j) .NE. River%basinid(i_nbr,j_nbr)) then write(stdout(),*) 'at (i,j) = (', i, ',',j, & '), basinid = ', River%basinid(i,j), ',tocell = (', i_nbr, ',', j_nbr, & ') with basinid = ', River%basinid(i_nbr, j_nbr), & River%travel(i,j), River%mask(i,j), River%travel(i_nbr,j_nbr), River%mask(i_nbr,j_nbr) call mpp_error(FATAL,"Every cell should have the same basinid as its tocell") end if call get_nbr_index(River%fromcell(i_nbr,j_nbr), i_nbr, j_nbr, i_array, j_array, num_nbrs) if(count(i_array(1:num_nbrs) == i .AND. j_array(1:num_nbrs) == j) .NE. 1) then write(stdout(),*) 'at (i,j) = (', i, ',',j, '), all the fromcell of its tocell does not contain itself' call mpp_error(FATAL,"all the fromcell of its tocell does not contain itself") end if if( River%travel(i,j) .NE. River%travel(i_nbr,j_nbr) + 1 ) then write(stdout(),*) 'at (i,j) = (', i, ',',j, '), The travel does not equal to the travel of tocell + 1' call mpp_error(FATAL,"The travel does not equal to the travel of tocell + 1") end if end if end do end do !--- make sure no river point with travel = 0 and tocell > 0 if(ANY(River%travel(1:nlon,1:nlat) == 0 .AND. River%tocell(1:nlon,1:nlat) > 0) ) call mpp_error(FATAL, & "some river point have zero travel and nonzero tocell") end subroutine check_river_data !##################################################################### !--- write out river routing data subroutine write_river_regrid_data(River) type(river_regrid_type), intent(in) :: River integer :: unit type(axistype) :: axis_x, axis_y, axis_x_ocn, axis_y_ocn type(fieldtype) :: fld_basin, fld_basincells, fld_cellarea type(fieldtype) :: fld_disttoocean, fld_fromcell, fld_order, fld_subA type(fieldtype) :: fld_subL, fld_tocell, fld_travel, fld_celllength, fld_mask type(fieldtype) :: fld_neighbor, fld_land_order, fld_ocn_mask, fld_slope type(fieldtype) :: fld_ocn_lon, fld_ocn_lat real, allocatable :: tmp(:,:) call mpp_open(unit,trim(river_output_file), MPP_OVERWR, MPP_NETCDF, threading = MPP_SINGLE) !--- write out axis meta data --------------------------------------------- call mpp_write_meta(unit, axis_x,'lon','degree_east','Nominal Longitude of T-cell center', & cartesian ='X', data = River%lon ) call mpp_write_meta(unit, axis_y,'lat','degree_north','Nominal Latitude of T-cell center', & cartesian ='Y', data = River%lat ) call mpp_write_meta(unit, axis_x_ocn,'grid_x_ocn','degree_east','Nominal Longitude of T-cell center of ocean grid', & cartesian ='X', data = lon_ocn(:,1) ) call mpp_write_meta(unit, axis_y_ocn,'grid_y_ocn','degree_north','Nominal Latitude of T-cell center of ocean grid', & cartesian ='Y', data = lat_ocn(1,:) ) !--- write out field meta data --------------------------------------------- call mpp_write_meta(unit, fld_basin, (/axis_x, axis_y/), 'basin', & 'none','river basin id', pack=1, missing=missing_value ) call mpp_write_meta(unit, fld_basincells, (/axis_x, axis_y/), 'basincells', & 'none','number of cells in subbasin', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_slope, (/axis_x, axis_y/), 'So', & 'none','slope', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_cellarea, (/axis_x, axis_y/), 'cellarea', & 'm2','cell area', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_disttoocean, (/axis_x, axis_y/), 'disttoocean', & 'm','distance to ocean', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_fromcell, (/axis_x, axis_y/), 'fromcell', & 'none','sum of directions from upstream cells', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_order, (/axis_x, axis_y/), 'order', & 'none','Strahler stream order', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_subA, (/axis_x, axis_y/), 'subA', & 'm2','subbasin area', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_subL, (/axis_x, axis_y/), 'subL', & 'm','subbasin length', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_tocell, (/axis_x, axis_y/), 'tocell', & 'none','direction to downstream cell', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_travel, (/axis_x, axis_y/), 'travel', & 'none','cells left to travel before reaching ocean', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_celllength, (/axis_x, axis_y/), 'celllength', & 'm','cell length', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_mask, (/axis_x, axis_y/), 'mask', & 'none','land/sea mask(land = 1)', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_neighbor, (/axis_x, axis_y/), 'neighbor', & 'none','neighbor point', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_land_order, (/axis_x, axis_y/), 'land_order', & 'none','neighbor point', pack=1, missing=missing_value) call mpp_write_meta(unit, fld_ocn_lon, (/axis_x_ocn, axis_y_ocn/), 'lon_ocean', & 'none','geographical longitude of ocean grid', pack=1) call mpp_write_meta(unit, fld_ocn_lat, (/axis_x_ocn, axis_y_ocn/), 'lat_ocean', & 'none','geographical latitude of ocean grid', pack=1) call mpp_write_meta(unit, fld_ocn_mask, (/axis_x_ocn, axis_y_ocn/), 'mask_ocean', & 'none','land/sea mask of ocean grid', pack=1) call mpp_write(unit, axis_x) call mpp_write(unit, axis_y) call mpp_write(unit, axis_x_ocn) call mpp_write(unit, axis_y_ocn) allocate(tmp(nlon, nlat) ) tmp = River%basinid(1:nlon,1:nlat) call mpp_write(unit, fld_basin, tmp) tmp = River%basincells(1:nlon,1:nlat) call mpp_write(unit, fld_basincells, tmp) call mpp_write(unit, fld_slope, River%slope(1:nlon,1:nlat)) call mpp_write(unit, fld_cellarea, River%cellarea(1:nlon,1:nlat)) call mpp_write(unit, fld_disttoocean, River%disttoocean(1:nlon,1:nlat)) tmp = River%fromcell(1:nlon,1:nlat) call mpp_write(unit, fld_fromcell, tmp) tmp = River%order(1:nlon,1:nlat) call mpp_write(unit, fld_order, tmp) call mpp_write(unit, fld_subA, River%subA(1:nlon,1:nlat)) call mpp_write(unit, fld_subL, River%subL(1:nlon,1:nlat)) tmp = River%tocell(1:nlon,1:nlat) call mpp_write(unit, fld_tocell, tmp) tmp = River%travel(1:nlon,1:nlat) call mpp_write(unit, fld_travel, tmp) call mpp_write(unit, fld_celllength, River%celllength(1:nlon,1:nlat)) call mpp_write(unit, fld_mask, River%mask(1:nlon,1:nlat)) tmp = River%neighbor(1:nlon,1:nlat) call mpp_write(unit, fld_neighbor, tmp) tmp = River%land_order(1:nlon,1:nlat) call mpp_write(unit, fld_land_order, tmp) call mpp_write(unit, fld_ocn_lon, lon_ocn ) call mpp_write(unit, fld_ocn_lat, lat_ocn ) call mpp_write(unit, fld_ocn_mask, mask_ocn ) call mpp_close(unit) deallocate(tmp) end subroutine write_river_regrid_data !##################################################################### ! release memory subroutine river_regrid_end(River) type(river_regrid_type), intent(inout) :: River module_is_initialized = .FALSE. deallocate(River%lonb, River%latb, River%cellarea, River%subL, River%subA ) deallocate(River%disttoocean, River%celllength, River%order ) deallocate(River%basinid, River%tocell, River%fromcell, River%basincells ) deallocate(River%travel, River%mask, River%neighbor, River%land_order ) deallocate(River%dist, River%lon, River%lat ) end subroutine river_regrid_end !##################################################################### !--- read river source data subroutine read_river_src_data type(axistype), dimension(:), allocatable :: axes, axes_bounds type(fieldtype), dimension(:), allocatable :: fields real, dimension(:,:), allocatable :: tmp real :: old_missing_value integer :: unit, n, m, ndim, nvar, natt, ntime, len_axes, nlon_src, nlat_src character(len=128) :: name character(len=1) :: cart logical :: found_cellarea, found_tocell, found_fromcell, found_basin, found_so logical :: found_basincells, found_order, found_travel, found_subL logical :: found_subA, found_disttoocean, found_dx write(stdout(),*) ' read river src data from file '//trim(river_input_file) if(.not. file_exist(trim(river_input_file))) & call mpp_error(FATAL, 'river_regrid: file '//trim(river_input_file)//' does not exist') !--- get the grid size and grids call mpp_open(unit,trim(river_input_file),action=MPP_RDONLY,form=MPP_NETCDF) call mpp_get_info(unit, ndim, nvar, natt, ntime) allocate(fields(nvar)) call mpp_get_fields(unit,fields) found_cellarea = .false. do n = 1, nvar call mpp_get_atts(fields(n),name=name) if(trim(name) == "cellarea") then found_cellarea = .true. ndim = 2 allocate(axes(ndim), axes_bounds(ndim)) call mpp_get_atts(fields(n),axes=axes) do m = 1, ndim cart = 'N' call get_axis_cart(axes(m), cart) call mpp_get_atts(axes(m),len=len_axes) if (cart == 'N') call mpp_error(FATAL,'river_routing_mod: couldnt recognize axis atts.') select case (cart) case ('X') nlon_src = len_axes allocate(Source%lonb(nlon_src+1), Source%lon(nlon_src)) call mpp_get_axis_data(axes(m), Source%lon) call get_axis_bounds(axes(m), axes_bounds(m), axes) call mpp_get_axis_data(axes_bounds(m), Source%lonb) case ('Y') nlat_src = len_axes allocate(Source%latb(nlat_src+1), Source%lat(nlat_src)) call mpp_get_axis_data(axes(m), Source%lat) call get_axis_bounds(axes(m), axes_bounds(m), axes) call mpp_get_axis_data(axes_bounds(m), Source%latb) end select enddo exit end if end do if(.not. found_cellarea) call mpp_error(FATAL,'river_routing_mod: cellarea is not in file '//trim(river_input_file) ) Source%nlon = nlon_src Source%nlat = nlat_src !--- read the field allocate(Source%cellarea (nlon_src,nlat_src), Source%tocell (nlon_src,nlat_src) ) allocate(Source%fromcell (nlon_src,nlat_src), Source%basinid (nlon_src,nlat_src) ) allocate(Source%basincells (nlon_src,nlat_src), Source%travel (nlon_src,nlat_src) ) allocate(Source%subL (nlon_src,nlat_src), Source%subA (nlon_src,nlat_src) ) allocate(Source%disttoocean(nlon_src,nlat_src) ) allocate(Source%celllength (nlon_src,nlat_src), Source%order (nlon_src,nlat_src) ) allocate(Source%slope (nlon_src,nlat_src), tmp (nlon_src,nlat_src) ) found_cellarea = .FALSE. ; found_tocell = .FALSE. found_fromcell = .FALSE. ; found_basin = .FALSE. found_basincells = .FALSE. ; found_order = .FALSE. found_travel = .FALSE. ; found_subL = .FALSE. found_subA = .FALSE. found_disttoocean = .FALSE. ; found_dx = .FALSE. do n = 1, nvar call mpp_get_atts(fields(n),name=name, missing = old_missing_value) select case (trim(name)) case ('So') found_so = .TRUE. call mpp_read(unit,fields(n), Source%slope ) where(Source%Slope == old_missing_value) Source%slope = missing_value case ('cellarea') found_cellarea = .TRUE. call mpp_read(unit,fields(n), Source%cellarea ) where(Source%cellarea == old_missing_value) Source%cellarea = missing_value case ('tocell') found_tocell = .TRUE. call mpp_read(unit,fields(n), tmp ) Source%tocell = tmp where(Source%tocell == old_missing_value) Source%tocell = missing_value case ('fromcell') found_fromcell = .TRUE. call mpp_read(unit,fields(n), tmp ) Source%fromcell = tmp where(Source%fromcell == old_missing_value) Source%fromcell = missing_value case ('basin') found_basin = .TRUE. call mpp_read(unit,fields(n), tmp ) Source%basinid = tmp where(Source%basinid == old_missing_value) Source%basinid = missing_value case ('basincells') found_basincells = .TRUE. call mpp_read(unit,fields(n), tmp) Source%basincells = tmp where(Source%basincells == old_missing_value) Source%basincells = missing_value case ('order') found_order = .TRUE. call mpp_read(unit,fields(n), tmp ) Source%order = tmp where(Source%order == old_missing_value) Source%order = missing_value case ('travel') found_travel = .TRUE. call mpp_read(unit,fields(n), tmp ) Source%travel = tmp where(Source%travel == old_missing_value) Source%travel = missing_value case ('subL') found_subL = .TRUE. call mpp_read(unit,fields(n), Source%subL ) where(Source%subL == old_missing_value) Source%subL = missing_value case ('subA') found_subA = .TRUE. call mpp_read(unit,fields(n), Source%subA ) where(Source%subA == old_missing_value) Source%subA = missing_value case ('disttoocean') found_disttoocean = .TRUE. call mpp_read(unit,fields(n), Source%disttoocean ) where(Source%disttoocean == old_missing_value) Source%disttoocean = missing_value case ('dx') found_dx = .TRUE. call mpp_read(unit,fields(n), Source%celllength ) where(Source%celllength == old_missing_value) Source%celllength = missing_value end select enddo deallocate(tmp, axes, axes_bounds, fields ) if(.not. found_so) call mpp_error(FATAL,'river_routing_mod: So is not in file '//trim(river_input_file) ) if(.not. found_cellarea) call mpp_error(FATAL,'river_routing_mod: cellarea is not in file '//trim(river_input_file) ) if(.not. found_tocell) call mpp_error(FATAL,'river_routing_mod: tocell is not in file '//trim(river_input_file) ) if(.not. found_fromcell) call mpp_error(FATAL,'river_routing_mod: fromcell is not in file '//trim(river_input_file) ) if(.not. found_basin) call mpp_error(FATAL,'river_routing_mod: basin is not in file '//trim(river_input_file) ) if(.not. found_basincells) call mpp_error(FATAL,'river_routing_mod: basincells is not in file '//trim(river_input_file) ) if(.not. found_order) call mpp_error(FATAL,'river_routing_mod: order is not in file '//trim(river_input_file) ) if(.not. found_travel) call mpp_error(FATAL,'river_routing_mod: travel is not in file '//trim(river_input_file) ) if(.not. found_subL) call mpp_error(FATAL,'river_routing_mod: subL is not in file '//trim(river_input_file) ) if(.not. found_subA) call mpp_error(FATAL,'river_routing_mod: subA is not in file '//trim(river_input_file) ) if(.not. found_disttoocean) call mpp_error(FATAL,'river_routing_mod: disttoocean is not in file '//trim(river_input_file) ) if(.not. found_dx) call mpp_error(FATAL,'river_routing_mod: dx is not in file '//trim(river_input_file) ) call mpp_close(unit) end subroutine read_river_src_data !##################################################################### !--- extend river grid to match land grid !--- define land/sea mask for each grid. subroutine define_new_grid(River) type(river_regrid_type), intent(out) :: River integer :: num_lon_begin, num_lon_end, num_lat_begin, num_lat_end, nlon_src, nlat_src integer :: i, j, i_trans, j_trans, im1, ip1, jm1, jp1 real :: dx, dy write(stdout(),*) 'define new grid After coupled with ocean grid' !--- We assume river source grid always is uniform dx = Source%lonb(2) - Source%lonb(1) dy = Source%latb(2) - Source%latb(1) nlon_src = Source%nlon; nlat_src = Source%nlat !--- The river grid should be inside the land grid if(Source%lonb(1) .lt. lon_start .or. Source%lonb(nlon_src+1) .gt. lon_end .or. & Source%latb(1) .lt. lat_start .or. Source%latb(nlat_src+1) .gt. lat_end) & call mpp_error(FATAL,'river_regrid: static river grid is not inside the region bounded by '// & 'lon_start, lon_end, lat_start and lat_end' ) !--- find how many points need to be added at the begining and end call find_grid_addition(lon_start, lon_end, Source%lonb(1), & Source%lonb(size(Source%lonb)), dx, num_lon_begin, num_lon_end) call find_grid_addition(lat_start, lat_end, Source%latb(1), & Source%latb(size(Source%latb)), dy, num_lat_begin, num_lat_end) River%nlon = nlon_src + num_lon_begin + num_lon_end River%nlat = nlat_src + num_lat_begin + num_lat_end nlon = River%nlon nlat = River%nlat !--- memory allocation allocate(River%lonb(nlon+1), River%latb(nlat+1), River%cellarea(nlon,nlat) ) allocate(River%subL(0:nlon+1,0:nlat+1), River%subA(0:nlon+1,0:nlat+1) ) allocate(River%disttoocean(nlon,nlat) ) allocate(River%celllength(nlon,nlat), River%order(0:nlon+1,0:nlat+1) ) allocate(River%basinid(nlon,nlat), River%tocell(0:nlon+1,0:nlat+1) ) allocate(River%fromcell(nlon,nlat), River%basincells(nlon,nlat) ) allocate(River%travel(nlon,nlat), River%mask(-1:nlon+2,-1:nlat+2) ) allocate(River%neighbor(nlon,nlat), River%land_order(nlon,nlat) ) allocate(River%dist(nlon, nlat, 8), River%lon(nlon), River%lat(nlat) ) allocate(River%slope(nlon,nlat) ) !--- get the expanded river grid call grid_expansion(River%lonb, Source%lonb, lon_start, lon_end, dx, num_lon_begin, num_lon_end) call grid_expansion(River%latb, Source%latb, lat_start, lat_end, dy, num_lat_begin, num_lat_end) write(stdout(),*) num_lon_begin, 'points is added at the west bound. ', num_lon_end, 'points is added at the east bound' write(stdout(),*) num_lat_begin, 'points is added at the south bound. ', num_lat_end, 'points is added at the north bound' do i = 1, nlon River%lon(i) = ( River%lonb(i) + River%lonb(i+1) ) * 0.5 enddo do j = 1, nlat River%lat(j) = ( River%latb(j) + River%latb(j+1) ) * 0.5 enddo !--- fill it with nan value River%slope = missing_value River%cellarea = missing_value River%subL = missing_value River%subA = missing_value River%disttoocean = missing_value River%celllength = missing_value River%order = missing_value River%basinid = missing_value River%tocell = missing_value River%fromcell = missing_value River%basincells = missing_value River%travel = missing_value !--- file it with orginal grid data do j = 1, nlat_src do i = 1, nlon_src i_trans = num_lon_begin + i j_trans = num_lat_begin + j River%slope (i_trans,j_trans) = Source%slope (i,j) River%cellarea (i_trans,j_trans) = Source%cellarea (i,j) River%subL (i_trans,j_trans) = Source%subL (i,j) River%subA (i_trans,j_trans) = Source%subA (i,j) River%disttoocean(i_trans,j_trans) = Source%disttoocean(i,j) River%celllength (i_trans,j_trans) = Source%celllength (i,j) River%order (i_trans,j_trans) = Source%order (i,j) River%basinid (i_trans,j_trans) = Source%basinid (i,j) River%tocell (i_trans,j_trans) = Source%tocell (i,j) River%fromcell (i_trans,j_trans) = Source%fromcell (i,j) River%basincells (i_trans,j_trans) = Source%basincells (i,j) River%travel (i_trans,j_trans) = Source%travel (i,j) enddo enddo !--- we assume the cyclic condition River%order(0, 1:nlat) = River%order(nlon,1:nlat) River%order(nlon+1,1:nlat) = River%order(1, 1:nlat) River%subL (0, 1:nlat) = River%subL (nlon,1:nlat) River%subL (nlon+1,1:nlat) = River%subL (1, 1:nlat) River%subA (0, 1:nlat) = River%subA (nlon,1:nlat) River%subA (nlon+1,1:nlat) = River%subA (1, 1:nlat) !--- define the mask of river grid according to land grid mask. call define_river_mask(River) !--- here we suppose the cyclic condition exists River%tocell(0,1:nlat) = River%tocell(nlon,1:nlat) River%tocell(nlon+1,1:nlat) = River%tocell(1,1:nlat) !--- define the distance to the neighbor at each point River%dist = 1.0e20 do j = 1, nlat do i = 1, nlon ip1 = i + 1; im1 = i - 1 jp1 = j + 1; jm1 = j - 1 if(im1 == 0) im1 = nlon if(ip1 == nlon+1) ip1 = 1 River%dist(i,j,1) = dist(River%lon(i), River%lat(j), River%lon(ip1), River%lat(j) ) if(jm1 .ne. 0 ) then River%dist(i,j,2) = dist(River%lon(i), River%lat(j), River%lon(ip1), River%lat(jm1) ) River%dist(i,j,3) = dist(River%lon(i), River%lat(j), River%lon(i ), River%lat(jm1) ) River%dist(i,j,4) = dist(River%lon(i), River%lat(j), River%lon(im1), River%lat(jm1) ) endif River%dist(i,j,5) = dist(River%lon(i), River%lat(j), River%lon(im1), River%lat(j) ) if(jp1 .ne. nlat+1) then River%dist(i,j,6) = dist(River%lon(i), River%lat(j), River%lon(im1), River%lat(jp1) ) River%dist(i,j,7) = dist(River%lon(i), River%lat(j), River%lon(i ), River%lat(jp1) ) River%dist(i,j,8) = dist(River%lon(i), River%lat(j), River%lon(ip1), River%lat(jp1) ) endif enddo enddo next_basinid = maxval(Source%basinid) + 1 end subroutine define_new_grid !##################################################################### !--- find number of points needed to be extended. subroutine find_grid_addition(lnd_start, lnd_end, river_start, river_end, dx, num_begin, num_end) real, intent(in) :: lnd_start, lnd_end, river_start, river_end, dx integer, intent(out) :: num_begin, num_end real :: diff, min_size min_size = 0.05 if(dx .lt. min_size) call mpp_error(FATAL,'river_routing_mod: river grid size is too small') !---first check how many points we need to add at the begining. num_begin = 0 diff = river_start - lnd_start if( diff .gt. min_size) then num_begin = int(diff / dx) if(diff-num_begin*dx .gt. min_size) num_begin = num_begin + 1 endif num_end = 0 diff = lnd_end - river_end if( diff .gt. min_size) then num_end = int(diff / dx) if(diff-num_end*dx .gt. min_size) num_end = num_end + 1 endif end subroutine find_grid_addition !##################################################################### !--- define new river grid subroutine grid_expansion(river_grid, orig_grid, lnd_start,lnd_end, dx, num_begin, num_end) real, dimension(:), intent(out) :: river_grid real, dimension(:), intent(in) :: orig_grid real, intent(in) :: lnd_start, lnd_end, dx integer, intent(in) :: num_begin, num_end integer :: num_orig, i num_orig = size(orig_grid) river_grid(num_begin+1:num_begin+num_orig) = orig_grid(:) do i=num_begin,2,-1 river_grid(i) = orig_grid(1) - (num_begin-i+1)*dx enddo if(num_begin .gt. 0) river_grid(1) = lnd_start do i=1,num_end-1 river_grid(num_begin+num_orig+i) = orig_grid(num_orig)+dx*i enddo if(num_end .gt. 0) river_grid(size(river_grid)) = lnd_end return end subroutine grid_expansion !##################################################################### !--- define land order for new river grid. subroutine define_new_land_order(River) type(river_regrid_type), intent(inout) :: River integer, dimension(:,:), allocatable :: land_order integer :: i, j, num_order logical :: found_new_land_pt write(stdout(),*) 'define land order for new river grid.' allocate(land_order(0:nlon+1,0:nlat+1) ) !---set the initial value to some dummy number land_order = -1 where( River%mask(1:nlon,1:nlat) .gt. lnd_thresh .and. River%travel(1:nlon,1:nlat) .eq. missing_value ) land_order(1:nlon,1:nlat) = 0 ! new land point end where !--- continue if there is any new land point to check !--- first find the coastal points River%neighbor = 0 do j = 1, nlat do i = 1, nlon if(land_order(i,j) == 0) then River%neighbor(i,j) = get_neighbor( River%mask(i-1:i+1,j-1:j+1) .le. lnd_thresh ) if(River%neighbor(i,j) .gt. 0) land_order(i,j) = 1 endif enddo enddo land_order(0,1:nlat) = land_order(nlon,1:nlat) land_order(nlon+1,1:nlat) = land_order(1,1:nlat) num_order = 2 do while(any(land_order(1:nlon,1:nlat) == 0) ) found_new_land_pt = .FALSE. do j = 1, nlat do i = 1, nlon if(land_order(i,j) == 0) then River%neighbor(i,j) = get_neighbor(land_order(i-1:i+1,j-1:j+1) .eq. num_order-1) if( River%neighbor(i,j) .gt. 0 ) then found_new_land_pt = .true. land_order(i,j) = num_order if(i == 1) land_order(nlon+1,j) = num_order if(i == nlon) land_order(0,j) = num_order endif endif enddo enddo if(.not. found_new_land_pt ) exit num_order = num_order + 1 enddo River%land_order(1:nlon,1:nlat) = land_order(1:nlon,1:nlat) deallocate(land_order) return end subroutine define_new_land_order !##################################################################### !--- define river routing data for new river grid subroutine define_new_land_data(River) type(river_regrid_type), intent(inout) :: River integer :: max_land_order, num_nbrs, num_max_order, num_max_subL integer :: i, j, k, n, i_lo, the_basinid, ii, jj, num_max_subA, fromcell logical :: is_neighbor(8) integer :: i_nbr, j_nbr, i_array(8), j_array(8), i_in(8), j_in(8), i_out(8), j_out(8) integer :: basinid_cur !--- first initialialize some field do j = 1, nlat do i = 1, nlon if(River%land_order(i,j) .ge. 0) then River%tocell(i,j) = 0 River%fromcell(i,j) = 0 River%travel(i,j) = 0 River%disttoocean(i,j) = 0 River%celllength(i,j) = 0 end if end do end do !--- first define the outflow direction for new land grid do j = 1, nlat do i = 1, nlon if(River%land_order(i,j) .ge. 1) then do k = 1,8 is_neighbor(k) = btest(River%neighbor(i,j),k-1) enddo River%tocell(i,j) = outflow_direction(is_neighbor, River%dist(i,j,:)) endif enddo enddo !--- update halo points of tocell River%tocell(0,1:nlat) = River%tocell(nlon,1:nlat) River%tocell(nlon+1,1:nlat) = River%tocell(1,1:nlat) !--- then define the inflow direction for new land grid do j = 1, nlat do i = 1, nlon if(River%land_order(i,j) .ge. 1) then River%fromcell(i,j) = inflow_direction(River%tocell(i-1:i+1,j-1:j+1)) else if(River%land_order(i,j) ==0) then fromcell = inflow_direction(River%tocell(i-1:i+1,j-1:j+1)) if(fromcell >0) then River%fromcell(i,j) = fromcell River%land_order(i,j) = 1 end if endif enddo enddo !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. ! **************************************************************** ! * Update properties of new land cells * ! * (and attributes of other cells impacted by the new land) * ! **************************************************************** ! First: properties that are only about each individual cell ! only have to define these for the new points added to the system do j = 1, nlat do i = 1, nlon River%cellarea(i,j) = area(River%lonb(i:i+1), River%latb(j:j+1) ) if(River%land_order(i,j) .ge. 1) then ! River%cellarea(i,j) = area(River%lonb(i:i+1), River%latb(j:j+1) ) if(River%tocell(i,j) ==0) cycle call get_nbr_index(River%tocell(i,j), i, j, i_array, j_array, num_nbrs) if(num_nbrs .ne. 1) call mpp_error(FATAL,'River can only flow to one direction') i_nbr = i_array(1) j_nbr = j_array(1) River%celllength(i,j) = dist(River%lon(i),River%lat(j), River%lon(i_nbr), River%lat(j_nbr) ) endif enddo enddo !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. !--multiple river%mask to get partial cellarea and remove previously land point do j = 1, nlat do i = 1, nlon if(River%cellarea(i,j) .NE. missing_value) then River%cellarea(i,j) = River%cellarea(i,j) *River%mask(i,j) end if end do end do !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. ! Now update properties that are dependent on upstream cells (fromcell) ! Need to do this from the inner-most new land points downstream toward the ocean ! Loop: for new points, from max(River%land_order(i,j)) to 1, counting down max_land_order = maxval(River%land_order) do i_lo = max_land_order, 1, -1 do j = 1, nlat do i = 1, nlon if (River%land_order(i,j) .eq. i_lo) then !--- find neighbors -------------- call get_nbr_index(River%fromcell(i,j), i,j,i_array, j_array, num_nbrs) ! No neighbors feed this cell (fromcell = 0) if (num_nbrs .eq. 0) then River%basinid(i,j) = next_basinid next_basinid = next_basinid + 1 River%order(i,j) = 1 River%subL(i,j) = River%celllength(i,j) River%subA(i,j) = River%cellarea(i,j) River%basincells(i,j) = 1 ! only one neighbor feeds this cell else if(num_nbrs == 1 ) then i_nbr = i_array(1) j_nbr = j_array(1) River%order(i,j) = River%order(i_nbr,j_nbr) River%basinid(i,j) = River%basinid(i_nbr,j_nbr) River%subL(i,j) = River%celllength(i,j) + River%subL(i_nbr,j_nbr) River%subA(i,j) = River%cellarea(i,j) + River%subA(i_nbr,j_nbr) River%basincells(i,j) = 1 + River%basincells(i_nbr,j_nbr) else ! multiple neighbors feed this cell ! one neighbor is the clear mainstem (by stream order) i_in(1:num_nbrs) = i_array(1:num_nbrs) j_in(1:num_nbrs) = j_array(1:num_nbrs) call find_max_int ( River%order, i_in, j_in, num_nbrs, i_out, j_out, num_max_order ) if( num_max_order == 1) then i_nbr = i_out(1) j_nbr = j_out(1) River%order(i,j) = River%order(i_nbr,j_nbr) ! no neighbor is the clear mainstem (by stream order) else ! multiple neighbors feeding in have the same, max(order)) ! determine mainstem by largest subL, then largest subA, then arbitrary i_in(1:num_max_order) = i_out(1:num_max_order) j_in(1:num_max_order) = j_out(1:num_max_order) call find_max_real( River%subL, i_in, j_in, num_max_order, i_out, j_out, num_max_subL ) if(num_max_subL == 1) then i_nbr = i_out(1) j_nbr = j_out(1) River%order(i,j) = 1 + River%order(i_nbr,j_nbr) else i_in(1:num_max_subL) = i_out(1:num_max_subL) j_in(1:num_max_subL) = j_out(1:num_max_subL) call find_max_real( River%subA, i_in, j_in, num_max_subL, i_out, j_out, num_max_subA ) if(num_max_subA == 1) then i_nbr = i_out(1) j_nbr = j_out(1) River%order(i,j) = 1 + River%order(i_nbr,j_nbr) else i_nbr = i_out(1) j_nbr = j_out(1) River%order(i,j) = 1 + River%order(i_nbr,j_nbr) write(stdout(),*) 'i,j, num_max_subA, i_out, j_out', i,j, & num_max_subA, i_out(1:num_max_subA), j_out(1:num_max_subA) call mpp_error(NOTE,'river_routing_mod: that is impossible') endif endif endif ! These properties depend on only one input cell River%basinid(i,j) = River%basinid(i_nbr,j_nbr) River%subL(i,j) = River%celllength(i,j) + River%subL(i_nbr,j_nbr) River%subA(i,j) = River%cellarea(i,j) River%basincells(i,j) = 1 do n = 1, num_nbrs River%subA(i,j) = River%subA(i,j) + River%subA(i_array(n),j_array(n)) River%basincells(i,j) = River%basincells(i,j) + River%basincells(i_array(n),j_array(n)) enddo ! These properties depend on all the input neighbor cells ! River%subA(i,j) = River%cellarea(i,j) + SUMOVER_NEIGHBORS(River%subA(?,?)) ! River%basincells(i,j) = 1 + SUMOVER_NEIGHBORS(River%basincells(?,?)) ! update basinid of other neighbors of point (i,j) do n = 1, num_nbrs where(River%basinid == River%basinid(i_array(n),j_array(n)) ) & River%basinid = River%basinid(i,j) enddo endif if(i == 1) then River%order(nlon+1,j) = River%order(i,j) River%subL(nlon+1,j) = River%subL(i,j) else if(i == nlon) then River%order(0,j) = River%order(i,j) River%subL(0,j) = River%subL(i,j) endif endif enddo enddo enddo !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. ! Now update properties that are dependent on downstream cells (tocell) ! Loop: start at the coast and move upstream do i_lo = 1, max_land_order do j = 1, nlat do i = 1, nlon if (River%land_order(i,j) .eq. i_lo) then River%travel(i,j) = River%land_order(i,j) - 1 if (River%travel(i,j) .eq. 0) then River%disttoocean(i,j) = River%celllength(i,j) else call get_nbr_index(River%tocell(i,j), i, j, i_array, j_array, num_nbrs) i_nbr = i_array(1) j_nbr = j_array(1) River%disttoocean(i,j) = River%celllength(i,j) + River%disttoocean(i_nbr,j_nbr) endif endif enddo enddo enddo !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. ! Now must update pre-existing network (anywhere that it used to go to the ocean and now it goes to land) ! Only the three cell attributes which depend on downstream cells need to be updated. do j = 1, nlat do i = 1, nlon if ((River%travel(i,j) .eq. 0) .and. (River%land_order(i,j) .lt. 0) ) then call get_nbr_index(River%tocell(i,j), i, j, i_array, j_array, num_nbrs) if(num_nbrs == 0) cycle i_nbr = i_array(1) j_nbr = j_array(1) if(River%land_order(i_nbr, j_nbr) .gt. 0) then River%travel(i,j) = River%travel(i_nbr, j_nbr) + 1 !River%travel(i,j) = River%travel(i,j) + River%travel(i_nbr, j_nbr) !??? River%disttoocean(i,j) = River%disttoocean(i,j) + River%disttoocean(i_nbr, j_nbr) the_basinid = River%basinid(i,j) do jj = 1, nlat do ii = 1, nlon if(River%land_order(ii,jj) .lt. 0 .and. River%basinid(ii,jj) .EQ. the_basinid) then if( is_connected(River%tocell(1:nlon,1:nlat), ii, jj, i, j) )then River%travel(ii,jj) = River%travel(ii,jj) + River%travel(i, j) River%disttoocean(ii,jj) = River%disttoocean(ii,jj) + River%disttoocean(i, j) endif endif enddo enddo endif endif enddo enddo !--- extend river with travel = 0 , tocell not zero, full land cell an extra points. !--- deal with in-land ocean, all the in-land ocean will be fefined as isolated river. do j = 1, nlat do i = 1, nlon if (River%land_order(i,j) == 0 ) then River%travel(i,j) = 0 River%basinid(i,j) = next_basinid next_basinid = next_basinid + 1 end if end do end do !--- the cell area will be cell area, not counted percentage of land do j = 1, nlat do i = 1, nlon River%cellarea(i,j) = area(River%lonb(i:i+1), River%latb(j:j+1) ) end do end do return end subroutine define_new_land_data !##################################################################### !--- this function will return an integer of power of 2. function outflow_direction(neighbor, dist) logical, dimension(:), intent(in) :: neighbor real, dimension(:), intent(in) :: dist integer :: outflow_direction integer :: max_count, max_adj, num_set, start(4) integer :: i, j, ii, n, outflow, num_min_points, index_min(8) logical :: keep_going real :: min_dist !--- first find the maximum adjacent ocean points start = 0 max_adj = 0 num_set = 1 i = 1 if(count(neighbor) == 8) then ! surrouding points are all ocean max_adj = 8 start = 1 else do while (i .le. 8) max_count = 0 if(neighbor(i)) then keep_going = .true. max_count = 1 j = i + 1 do while(keep_going) if(j .gt. 8) j = j-8 if(neighbor(j)) then max_count = max_count + 1 else keep_going = .false. exit endif j = j + 1 enddo if(max_count .gt. max_adj) then num_set = 1 max_adj = max_count start(num_set) = i else if(max_count .eq. max_adj) then num_set = num_set + 1 start(num_set) = i endif endif i = i + max_count + 1 enddo endif !--- find the outflow direction -------------------------------------- if(num_set .eq. 1 .and. mod(max_adj,2) == 1) then !--- There will be a center point if max_adj is odd -------------- outflow = start(1) + max_count/2 if(outflow .gt. 8) outflow = outflow - 8 else !--- find the shortest distance point min_dist = dist(start(1)) num_min_points = 1 index_min(num_min_points) = start(num_set) do n = 1, num_set do i = 1, max_adj - 1 ii = start(n)+i if(ii .gt. 8 ) ii = ii - 8 if(dist(ii) .lt. min_dist) then min_dist = dist(ii) num_min_points = 1 index_min(1) = ii else if(dist(ii) .eq. min_dist) then num_min_points = num_min_points + 1 index_min(num_min_points) = ii endif enddo enddo if(num_min_points .eq. 1) then outflow = index_min(num_min_points) else outflow = random_select(index_min(1:num_min_points)) endif endif outflow_direction = 2 ** (outflow - 1) return end function outflow_direction !##################################################################### !--- calculate inflow direction from outflow data. function inflow_direction(outflow) integer, dimension(:,:), intent(in) :: outflow integer :: inflow_direction integer :: i, j i = 2; j = 2 inflow_direction = 0 if( outflow(i+1,j) == 16 ) inflow_direction = inflow_direction + 1 if( outflow(i+1,j-1) == 32) inflow_direction = inflow_direction + 2 if( outflow(i,j-1) == 64) inflow_direction = inflow_direction + 4 if( outflow(i-1,j-1) == 128) inflow_direction = inflow_direction + 8 if( outflow(i-1,j) == 1) inflow_direction = inflow_direction + 16 if( outflow(i-1,j+1) == 2) inflow_direction = inflow_direction + 32 if( outflow(i,j+1) == 4) inflow_direction = inflow_direction + 64 if( outflow(i+1,j+1) == 8) inflow_direction = inflow_direction + 128 return end function inflow_direction !##################################################################### !--- find neighbor points. function get_neighbor(is_neighbor ) logical, dimension(:,:), intent(in) :: is_neighbor integer :: get_neighbor integer :: i,j i=2; j=2 get_neighbor = 0 if(is_neighbor(i+1,j)) get_neighbor = get_neighbor + 1 if(is_neighbor(i+1,j-1)) get_neighbor = get_neighbor + 2 if(is_neighbor(i,j-1)) get_neighbor = get_neighbor + 4 if(is_neighbor(i-1,j-1)) get_neighbor = get_neighbor + 8 if(is_neighbor(i-1,j)) get_neighbor = get_neighbor + 16 if(is_neighbor(i-1,j+1)) get_neighbor = get_neighbor + 32 if(is_neighbor(i,j+1)) get_neighbor = get_neighbor + 64 if(is_neighbor(i+1,j+1)) get_neighbor = get_neighbor + 128 return end function get_neighbor !##################################################################### ! --- this is only for rectangular grid -------------------------------------- function area(x, y) real, dimension(2), intent(in) :: x,y real :: area real :: dx dx = (x(2)-x(1)) * D2R if(dx > PI) dx = dx - 2.0*PI if(dx < -PI) dx = dx + 2.0*PI !??? Do we need to multiple radius*radius area = radius*radius*dx*(sin(y(2)*D2R) - sin(y(1)*D2R)) return end function area !##################################################################### !--- find the distance of any two grid. function dist(lon1, lat1, lon2, lat2) real, intent(in) :: lon1,lat1,lon2,lat2 real :: dist real :: s1, s2, dx dx = lon2 - lon1 if(dx .gt. 180.) dx = dx - 360. if(dx .lt. -180.) dx = dx + 360. if(lon1 == lon2) then dist = abs(lat2 - lat1) * D2R else if(lat1 == lat2) then dist = abs(dx) * D2R * cos(lat1*D2R) else ! diagonal distance s1 = abs(dx) * D2R * cos(lat1*D2R) s2 = abs(lat2 - lat1) * D2R dist = sqrt(s1*s1+s2*s2) endif dist = radius * dist return end function dist !##################################################################### !--- find the max value of real data array subroutine find_max_real(data, i_in, j_in, num_in, i_out, j_out, num_out) real, dimension(0:,0:), intent(in) :: data integer, dimension(:), intent(in) :: i_in, j_in integer, intent(in) :: num_in integer, dimension(:), intent(out) :: i_out, j_out integer, intent(out) :: num_out integer, dimension(num_in) :: index integer :: n i_out(1) = i_in(1) j_out(1) = j_in(1) index(1) = 1 num_out = 1 do n = 2, num_in if(data(i_in(n),j_in(n)) .gt. data(i_out(num_out), j_out(num_out))) then num_out = 1 i_out(num_out) = i_in(n) j_out(num_out) = j_in(n) index(num_out) = n else if(data(i_in(n),j_in(n)) .eq. data(i_out(num_out), j_out(num_out))) then num_out = num_out + 1 i_out(num_out) = i_in(n) j_out(num_out) = j_in(n) index(num_out) = n endif enddo return end subroutine find_max_real !##################################################################### !--- find the max value of integer data array subroutine find_max_int(data, i_in, j_in, num_in, i_out, j_out, num_out) integer, dimension(0:,0:), intent(in) :: data integer, dimension(:), intent(in) :: i_in, j_in integer, intent(in) :: num_in integer, dimension(:), intent(out) :: i_out, j_out integer, intent(out) :: num_out real, dimension(size(data,1), size(data,2) ) :: real_data real_data = data call find_max_real(real_data, i_in, j_in, num_in, i_out, j_out, num_out) return end subroutine find_max_int !##################################################################### !--- remove land point in source data but is ocean recognized by land model. subroutine trim_river(River) type(river_regrid_type), intent(inout) :: River integer, dimension(:,:), allocatable :: land_order integer :: i, j logical :: need_to_modify write(stdout(),*) 'remove previously land point ( is ocean after coupled with land grid). ' !---set the initial value to some dummy number allocate(land_order(nlon, nlat) ) land_order = -1 !---find points that have river network info but the land model thinks are ocean points do j = 1, nlat do i = 1, nlon if(River%mask(i,j) .lt. lnd_thresh .and. River%travel(i,j) .ne. missing_value ) land_order(i,j) = 1 enddo enddo !--- continue if there is any land point in the river network to change to ocean do while(any(land_order == 1) ) write(stdout(), *)' number of points land_order == 1', count(land_order == 1) write(stdout(), *)' number of points land_order == 1 and travel == 0', & count(land_order == 1.and. River%travel==0) if(.not.( any((land_order == 1) .and. (River%travel .eq. 0) ) .or. & any (land_order == 1 .and. River%travel .gt. 0 .and. River%fromcell .le. 0) ) )then do j = 1, nlat do i = 1, nlon if(land_order(i,j) == 1) then write(stdout(),*)i,j, River%lon(i), & River%lat(j), land_order(i,j), River%travel(i,j) endif enddo enddo exit endif do j =1, nlat do i =1, nlon !--- first situation: The previously land point is at coast. if(land_order(i,j) == 1) then need_to_modify = .false. if(River%travel(i,j) .eq. 0) then call update_upstream(River,land_order, i,j) ! coast point need_to_modify = .true. !--- second situation: The previously land point is not at coast and is start point of a river else if(River%travel(i,j) .gt. 0 .and. River%fromcell(i,j) .le. 0) then call update_downstream(River,i,j) need_to_modify = .true. endif if(need_to_modify) then land_order(i,j) = -1 !--- return it to dummy value !--- fill it with nan value River%cellarea(i,j) = missing_value River%subL(i,j) = missing_value River%subA(i,j) = missing_value River%disttoocean(i,j) = missing_value River%celllength(i,j) = missing_value River%order(i,j) = missing_value River%basinid(i,j) = missing_value River%tocell(i,j) = missing_value River%fromcell(i,j) = missing_value River%basincells(i,j) = missing_value River%travel(i,j) = missing_value endif endif enddo enddo enddo do while(any(land_order == 1) ) write(stdout(), *)' number of points land_order == 1', count(land_order == 1) if(.not. any(land_order == 1 .and. River%travel .gt. 0 .and. River%fromcell .gt. 0) ) & call mpp_error(FATAL,'infinity loop') do j =1, nlat do i =1, nlon !--- first situation: The previously land point is at coast. if(land_order(i,j) == 1) then if(River%travel(i,j) .gt. 0) then if(River%fromcell(i,j) .gt. 0) call update_upstream(River,land_order,i,j) call update_downstream(River,i,j) endif land_order(i,j) = -1 !--- return it to dummy value !--- fill it with nan value River%cellarea(i,j) = missing_value River%subL(i,j) = missing_value River%subA(i,j) = missing_value River%disttoocean(i,j) = missing_value River%celllength(i,j) = missing_value River%order(i,j) = missing_value River%basinid(i,j) = missing_value River%tocell(i,j) = missing_value River%fromcell(i,j) = missing_value River%basincells(i,j) = missing_value River%travel(i,j) = missing_value endif enddo enddo enddo end subroutine trim_river !##################################################################### !--- update downstream points. subroutine update_downstream(River,i,j) type(river_regrid_type), intent(inout) :: River integer, intent(in) :: i,j integer :: i_array(8), j_array(8), i_in(8), j_in(8), i_out(8), j_out(8) integer :: i_nbr,j_nbr, ii,jj, iii, jjj, num_nbrs integer :: num_max_subL, num_max_subA, num_max_order, n, nn logical :: keep_going call get_nbr_index(River%tocell(i,j), i, j, i_array, j_array, num_nbrs) if(num_nbrs .NE. 1) return i_nbr = i_array(1); j_nbr = j_array(1) if(River%fromcell(i_nbr,j_nbr) == missing_value) return call get_nbr_index(River%fromcell(i_nbr,j_nbr), i_nbr, j_nbr, i_array, j_array, num_nbrs) ii = i_nbr; jj = j_nbr iii = i; jjj = j do while (River%tocell(ii,jj) .gt. 0) call get_nbr_index(River%fromcell(ii,jj), ii, jj, i_array, j_array, num_nbrs) if(num_nbrs == 1) then if(i_array(1) == i .and. j_array(1) == j) then River%order(ii,jj) = 1 else River%order(ii,jj) = River%order(i_array(1), j_array(1)) endif River%subL(ii,jj) = River%subL(ii,jj) - River%subL(i,j) else !--- first find the largest order i_in(1:num_nbrs) = i_array(1:num_nbrs) j_in(1:num_nbrs) = j_array(1:num_nbrs) call find_max_int ( River%order, i_in, j_in, num_nbrs, i_out, j_out, num_max_order ) ! if (iii,jjj) is not among the points with max order, we can stop keep_going = .false. do n = 1, num_max_order if(i_out(n) .eq. iii .and. j_out(n) .eq. jjj) keep_going = .true. enddo if(.not. keep_going) exit if( num_max_order == 1) then River%subL(ii,jj) = River%subL(ii,jj) - River%subL(i,j) nn = 0 do n = 1, num_nbrs if( .not. (i_in(n) == i .and. j_in(n) == j ) ) then nn = nn + 1 i_in(nn) = i_in(n) j_in(nn) = j_in(n) endif enddo call find_max_int(River%order, i_in, j_in, nn, i_out, j_out, num_max_order) if(num_max_order == 1 )then River%order(ii,jj) = River%order(i_out(1), j_out(1) ) else River%order(ii,jj) = River%order(i_out(1), j_out(1) ) + 1 endif ! no neighbor is the clear mainstem (by stream order) else ! multiple neighbors feeding in have the same, max(order)) ! determine mainstem by largest subL, then largest subA, then arbitrary !--- if num_max_order is greater than 2, do not need to modify order. if(num_max_order .gt. 2) exit if(iii == i .and. jjj == j) then !--- (iii, jjj ) is the point we are going to remove keep_going = .false. do n = 1, num_max_order if( i_out(n) .eq. i .and. j_out(n) .eq. j) then River%order(ii,jj) = River%order(i_out(1), j_out(1) ) keep_going = .true. endif enddo else !--- (iii, jjj ) is not the point we are going to remove if(River%order(ii,jj) == River%order(i_out(1), j_out(1)) +1 ) then keep_going = .false. else River%order(ii,jj) = River%order(i_out(1), j_out(1) ) + 1 endif endif if(.not. keep_going) exit !--- change subL. i_in(1:num_max_order) = i_out(1:num_max_order) j_in(1:num_max_order) = j_out(1:num_max_order) call find_max_real( River%subL, i_in, j_in, num_max_order, i_out, j_out, num_max_subL ) if(num_max_subL == 1) then if(i_out(1) .eq. iii .and. j_out(1) .eq. jjj) then River%subL(ii,jj) = River%subL(ii,jj) - River%subL(i,j) else exit endif else i_in(1:num_max_subL) = i_out(1:num_max_subL) j_in(1:num_max_subL) = j_out(1:num_max_subL) call find_max_real( River%subA, i_in, j_in, num_max_subL, i_out, j_out, num_max_subA ) if(num_max_subA == 1) then if(i_out(1) .eq. iii .and. j_out(1) .eq. jjj) then River%subL(ii,jj) = River%subL(ii,jj) - River%subL(i,j) else exit endif else exit call mpp_error(FATAL,'river_routing_mod: that is impossible') endif endif endif endif call get_nbr_index(River%tocell(ii,jj), ii, jj, i_array, j_array, num_nbrs) iii = ii; jjj = jj ii = i_array(1); jj = j_array(1) enddo ii = i_nbr; jj = j_nbr do while(River%tocell(ii,jj) > 0) River%subA(ii,jj) = River%subA(ii,jj) - River%subA(i,j) River%basincells(ii,jj) = River%basincells(ii,jj) - River%basincells(i,j) call get_nbr_index(River%tocell(ii,jj), ii, jj, i_array, j_array, num_nbrs) if(num_nbrs .ne. 1) then call mpp_error(FATAL,'num_nbrs should be 1 here' ) endif ii = i_array(1); jj = j_array(1) enddo if(River%tocell(i,j) .lt. 16) then River%fromcell(i_nbr,j_nbr) = River%fromcell(i_nbr,j_nbr) - River%tocell(i,j)*16 else if(River%tocell(i,j) .ge. 16) then River%fromcell(i_nbr,j_nbr) = River%fromcell(i_nbr,j_nbr) - River%tocell(i,j)/16 endif end subroutine update_downstream !####################################################################### !--- update upstream points subroutine update_upstream(River, land_order, i, j) type(river_regrid_type), intent(inout) :: River integer, dimension(:,:), intent(in) :: land_order integer, intent(in) :: i,j integer :: i_array(8), j_array(8) integer :: ii,jj, num_nbrs, n logical :: connect call get_nbr_index(River%fromcell(i,j), i, j, i_array, j_array, num_nbrs) do n = 1, num_nbrs !--- if the from cell also need to be removed, will update upstream through the from cell. if(land_order(i_array(n),j_array(n)) == 1) cycle River%basinid(i_array(n),j_array(n)) = next_basinid River%travel(i_array(n),j_array(n)) = River%travel(i_array(n),j_array(n)) - River%travel(i,j) - 1 River%disttoocean(i_array(n),j_array(n)) = & River%disttoocean(i_array(n),j_array(n)) - River%disttoocean(i,j) !--- Search all the points to see which point is connected with i_array(n), j_array(n) do jj = 1, nlat do ii = 1, nlon if(River%basinid(ii,jj) .eq. River%basinid(i,j) ) then connect = is_connected(River%tocell(1:nlon,1:nlat), ii, jj, i_array(n), j_array(n)) if( connect) then River%basinid(ii,jj) = next_basinid River%travel(ii,jj) = River%travel(ii,jj) - River%travel(i,j) - 1 River%disttoocean(ii,jj) = River%disttoocean(ii,jj) - River%disttoocean(i,j) endif endif enddo enddo next_basinid = next_basinid + 1 enddo end subroutine update_upstream !##################################################################### !--- check if two point are connected by a river function is_connected(tocell, i, j, i_dst, j_dst) integer, dimension(:,:), intent(in) :: tocell integer, intent(in) :: i, j, i_dst, j_dst logical :: is_connected integer :: cell, ii, jj, m, n, num_nbr, i_array(8), j_array(8) is_connected = .false. cell = tocell(i,j) ii = i; jj = j do while(cell .gt. 0) call get_nbr_index(cell, ii, jj, i_array, j_array, num_nbr) if(num_nbr .ne. 1) call mpp_error(FATAL,'river_regrid: num_nbr should be 1') m = i_array(1); n = j_array(1) if(m == i_dst .and. n == j_dst) then is_connected = .true. return else cell = tocell(m,n) ii = m; jj = n endif enddo end function is_connected !##################################################################### !--- random select a direction. function random_select(array) integer, dimension(:), intent(in) :: array integer :: random_select integer, save :: prev = 0 integer :: i, num_ele num_ele = size(array) do prev = prev + 1 if(prev .gt. 8) prev = prev - 8 do i = 1, num_ele if(array(i) .eq. prev) then random_select = prev return endif enddo enddo end function random_select !##################################################################### !--- get the index of neighbor point subroutine get_nbr_index(number, i_in, j_in, i_out, j_out, num_nbr) integer, intent(in) :: number !number should be between 0 to 255 integer, intent(in) :: i_in, j_in integer, dimension(:), intent(out) :: i_out, j_out integer, intent(out) :: num_nbr integer :: n num_nbr = 0 n = number if(n .ge. 128) then num_nbr = num_nbr + 1 n = n - 128 i_out(num_nbr) = i_in+1; j_out(num_nbr) = j_in + 1 endif if(n .ge. 64) then num_nbr = num_nbr + 1 n = n - 64 i_out(num_nbr) = i_in; j_out(num_nbr) = j_in + 1 endif if(n .ge. 32) then num_nbr = num_nbr + 1 n = n - 32 i_out(num_nbr) = i_in-1; j_out(num_nbr) = j_in + 1 endif if(n .ge. 16) then num_nbr = num_nbr + 1 n = n - 16 i_out(num_nbr) = i_in-1; j_out(num_nbr) = j_in endif if(n .ge. 8) then num_nbr = num_nbr + 1 n = n - 8 i_out(num_nbr) = i_in-1; j_out(num_nbr) = j_in - 1 endif if(n .ge. 4) then num_nbr = num_nbr + 1 n = n - 4 i_out(num_nbr) = i_in; j_out(num_nbr) = j_in - 1 endif if(n .ge. 2) then num_nbr = num_nbr + 1 n = n - 2 i_out(num_nbr) = i_in+1; j_out(num_nbr) = j_in - 1 endif if(n .ge. 1) then num_nbr = num_nbr + 1 n = n - 1 i_out(num_nbr) = i_in+1; j_out(num_nbr) = j_in endif do n = 1, num_nbr if(i_out(n) .eq. nlon+1) i_out(n) = 1 if(i_out(n) .eq. 0) i_out(n) = nlon if(j_out(n) .eq. 0 .or. j_out(n) .eq. nlat+1) & call mpp_error(FATAL,'river_regrid: neighbor latitude index should be between 1 and nj') enddo return end subroutine get_nbr_index !##################################################################### ! define river grid mask. river mask will be defined through ocean land/sea mask. ! conservative remapping will be done from ocean grid onto river grid. subroutine define_river_mask(River) type(river_regrid_type), intent(inout) :: River integer :: i, j, layout(2), isc, iec, jsc, jec integer :: siz(4), nlon_ocn, nlat_ocn real, dimension(:,:,:), allocatable :: x_vert_t, y_vert_t real, dimension(:,:), allocatable :: x_vert_ocn, y_vert_ocn real, dimension(:,:), allocatable :: local_mask, global_mask type(horiz_interp_type) :: Interp type(domain2D) :: Domain real :: diff real, parameter :: small = 1.e-6 River%mask = 0 ! 0 means ocean points !--- read ocean grid location and land/sea mask. call field_size(grid_file, 'wet', siz) nlon_ocn = siz(1) nlat_ocn = siz(2) allocate(x_vert_ocn(nlon_ocn+1, nlat_ocn+1)) allocate(y_vert_ocn(nlon_ocn+1, nlat_ocn+1)) allocate(mask_ocn (nlon_ocn, nlat_ocn )) allocate(lon_ocn (nlon_ocn, nlat_ocn )) allocate(lat_ocn (nlon_ocn, nlat_ocn )) call read_data(grid_file, 'wet', mask_ocn, no_domain=.true.) if(field_exist(grid_file, 'geolon_vert_t') )then call read_data(grid_file, 'geolon_vert_t', x_vert_ocn, no_domain=.true.) call read_data(grid_file, 'geolat_vert_t', y_vert_ocn, no_domain=.true.) call read_data(grid_file, 'geolon_t', lon_ocn, no_domain=.true.) call read_data(grid_file, 'geolat_t', lat_ocn, no_domain=.true.) else if(field_exist(grid_file, 'x_vert_T') )then allocate(x_vert_t(nlon_ocn, nlat_ocn, 4)) allocate(y_vert_t(nlon_ocn, nlat_ocn, 4)) call read_data(grid_file, 'x_vert_T', x_vert_t, no_domain=.true.) call read_data(grid_file, 'y_vert_T', y_vert_t, no_domain=.true.) call read_data(grid_file, 'x_T', lon_ocn, no_domain=.true.) call read_data(grid_file, 'y_T', lat_ocn, no_domain=.true.) x_vert_ocn(1:nlon_ocn,1:nlat_ocn) = x_vert_t(1:nlon_ocn,1:nlat_ocn,1) x_vert_ocn(nlon_ocn+1,1:nlat_ocn) = x_vert_t(nlon_ocn,1:nlat_ocn,2) x_vert_ocn(1:nlon_ocn,nlat_ocn+1) = x_vert_t(1:nlon_ocn,nlat_ocn,4) x_vert_ocn(nlon_ocn+1,nlat_ocn+1) = x_vert_t(nlon_ocn,nlat_ocn,3) y_vert_ocn(1:nlon_ocn,1:nlat_ocn) = y_vert_t(1:nlon_ocn,1:nlat_ocn,1) y_vert_ocn(nlon_ocn+1,1:nlat_ocn) = y_vert_t(nlon_ocn,1:nlat_ocn,2) y_vert_ocn(1:nlon_ocn,nlat_ocn+1) = y_vert_t(1:nlon_ocn,nlat_ocn,4) y_vert_ocn(nlon_ocn+1,nlat_ocn+1) = y_vert_t(nlon_ocn,nlat_ocn,3) deallocate(x_vert_t) deallocate(y_vert_t) else call mpp_error(FATAL,'river_regrid: both geolon_vert_t and x_vert_T do not exist in file '//trim(grid_file)) end if ! There is some truncation error in some latitude, adjust the small difference for non-folded region do j = 1, nlat_ocn+1 if(ANY( y_vert_ocn(:,j) .NE. y_vert_ocn(1,j)) ) exit diff = abs(y_vert_ocn(1,j) - int(y_vert_ocn(1,j))) if( diff < small .AND. diff > 0) then write(stdout(),*)'y_vert_ocn is adjusted from ', y_vert_ocn(1,j), ' to ', int(y_vert_ocn(1,j)), ' at j = ', j y_vert_ocn(:,j) = int(y_vert_ocn(1,j)) end if end do do j = 1, nlat_ocn if(ANY( lat_ocn(:,j) .NE. lat_ocn(1,j)) ) exit if( abs(lat_ocn(1,j) - int(lat_ocn(1,j))) < small ) then lat_ocn(:,j) = int(lat_ocn(1,j)) end if end do call horiz_interp_init ! The following procedure is very expensive, so parallization is needed call mpp_define_layout( (/1,nlon,1,nlat/), mpp_npes(), layout) call mpp_define_domains((/1,nlon,1,nlat/),layout, Domain,xhalo=0,yhalo=0) call mpp_get_compute_domain( Domain, isc, iec, jsc, jec ) call horiz_interp_new(Interp, x_vert_ocn*DEG_TO_RAD, y_vert_ocn*DEG_TO_RAD, River%lonb(isc:iec+1)*DEG_TO_RAD, & River%latb(jsc:jec+1)*DEG_TO_RAD, interp_method='conservative' ) allocate(local_mask(isc:iec,jsc:jec), global_mask(nlon,nlat)) call horiz_interp(Interp, mask_ocn, local_mask) call mpp_global_field(Domain, local_mask, global_mask) River%mask(1:nlon,1:nlat) = global_mask call horiz_interp_del(Interp) deallocate(x_vert_ocn, y_vert_ocn, local_mask, global_mask) !--- currently the mask is the ocean mask. do j = 1, nlat do i = 1, nlon River%mask(i,j) = 1 - River%mask(i,j) if( abs(River%mask(i,j)) < lnd_thresh ) River%mask(i,j) = 0.0 if( abs(River%mask(i,j)-1) < lnd_thresh) River%mask(i,j) = 1.0 if( River%mask(i,j) < 0 .or. River%mask(i,j) > 1) & call mpp_error(FATAL,'river_regrid: river mask should be between 0 or 1') end do end do !--- here we suppose the cyclic condition exists call update_halo(River%mask(-1:nlon+2,1:nlat), 2) !--- set mask to large positive value for the purpose of defining neighbor points. River%mask(:,-1:0) = 999.0 River%mask(:,nlat+1:nlat+2) = 999.0 end subroutine define_river_mask !##################################################################### !--- update point on the global halo. subroutine update_halo(data, halo) integer, intent(in) :: halo real, dimension(1-halo:,:), intent(inout) :: data integer :: n, ni ni = size(data,1) - 2*halo do n = 1, halo data(1-n,:) = data(ni+1-n,:) data(ni+n,:) = data(halo,:) enddo end subroutine update_halo !##################################################################### !--- read each line of the file grid_edits subroutine parse_edits(txt,is,ie,js,je,flag) character(len=*), intent(in) :: txt integer, intent(inout) :: is,ie,js,je logical, intent(inout) :: flag integer :: i1,i2, i3 character(len=128) :: txt2 flag = .true. i1 = scan(txt,',') if (i1 <= 0) goto 90 txt2 = txt(1:i1-1) i2 = scan(txt2,':') if (i2 <= 0) then read(txt2,*,err=90) is ie = is else read(txt2(1:i2-1),*,err=90) is read(txt2(i2+1:),*,err=90) ie endif txt2 = txt(i1+1:) i3 = scan(txt2,':') if (i3 <= 0) then read(txt2,*,err=90) js je = js else read(txt2(1:i3-1),*,err=90) js read(txt2(i3+1:),*,err=90) je endif return 90 continue flag = .false. return end subroutine parse_edits !##################################################################### end program river_regrid