|
| 1 | +#include "MAPL_ErrLog.h" |
| 2 | + |
| 3 | +module pfaf_fracMod |
| 4 | +!Main purpose: Assigns a catchment‐tile index from catchment definition files to each model grid cell for M36 grid. |
| 5 | +use MAPL |
| 6 | +use LogRectRasterizeMod, only: nc=>SRTM_maxcat |
| 7 | + |
| 8 | +implicit none |
| 9 | +private |
| 10 | + |
| 11 | +public :: get_Pfaf_frac |
| 12 | + |
| 13 | +contains |
| 14 | + |
| 15 | + subroutine get_Pfaf_frac(file_out, GridName) |
| 16 | + character(*), intent(in) :: file_out |
| 17 | + character(*), intent(in) :: GridName |
| 18 | + integer,parameter :: nlon=21600 ! Number of longitude grid points in the original grid |
| 19 | + integer,parameter :: nlat=10800 ! Number of latitude grid points in the original grid |
| 20 | + ! Variable declarations: |
| 21 | + integer :: id, xi, yi, i,j, flag, subi,nmax,nmax2,ntot,it,ns_tot |
| 22 | + integer,allocatable :: nsub(:) ! Array to store the number of sub-areas for each catchment |
| 23 | + integer, allocatable :: xsub(:,:), ysub(:,:), isub(:,:) |
| 24 | + ! xsub and ysub: 2D arrays to store mapped x and y indices for sub-catchments (not using subi_global in this code) |
| 25 | + real, allocatable :: asub(:,:) ! 2D array to store aggregated area for each sub-catchment |
| 26 | + |
| 27 | + real*8, allocatable :: lon(:), lat(:) ! Arrays to hold longitude and latitude values from the NetCDF file |
| 28 | + real*8, allocatable :: lons(:), lats(:) ! Arrays to hold longitude and latitude values from the NetCDF file |
| 29 | + integer, allocatable :: loni(:), lati(:) |
| 30 | + integer, allocatable :: loni2(:), lati2(:) |
| 31 | + ! loni and lati: Arrays holding mapping indices from 1-minute resolution data files |
| 32 | + integer, allocatable :: catchind(:,:) ! 2D array holding catchment indices for each grid cell |
| 33 | + real, allocatable :: cellarea(:,:) ! 2D array containing the area of each grid cell |
| 34 | + |
| 35 | + ! Declare allocatable arrays for catchment ID, parent catchment ID, and boundary coordinates |
| 36 | + integer, allocatable, dimension(:) :: tid, catid, lati_tile, loni_tile |
| 37 | + real*8, allocatable, dimension(:) :: lon_left, lon_right, lat_bottom, lat_top, latc,lonc |
| 38 | + integer,allocatable,dimension(:,:) :: map_tile |
| 39 | + |
| 40 | + real,allocatable,dimension(:) :: area_cat, pfaf_frac(:) |
| 41 | + real,allocatable,dimension(:,:) :: frac,frac_tile |
| 42 | + integer,allocatable,dimension(:) :: nsub_tile |
| 43 | + integer,allocatable ::csub(:,:),flag2(:,:), tile_id(:), pfaf_index(:) |
| 44 | + type(NetCDF4_FileFormatter) :: formatter |
| 45 | + type (FileMetadata) :: meta |
| 46 | + type(Variable) :: v |
| 47 | + integer :: nc_ease, nr_ease |
| 48 | + real :: tmp_lat, tmp_lon |
| 49 | + |
| 50 | + ! Define file path for input routing data: |
| 51 | + character(len=256) :: pfafData_file = "/discover/nobackup/projects/gmao/bcs_shared/make_bcs_inputs/land/topo/v1/SRTM-TopoData/SRTM_PfafData.nc" !"input/CatchIndex.nc" |
| 52 | + character(len=256) :: cellarea_file = "/discover/nobackup/projects/gmao/bcs_shared/test/stuff/route_model/v1/cellarea.nc" |
| 53 | + call MAPL_ease_extent( trim(GridName), nc_ease, nr_ease) |
| 54 | + |
| 55 | + ! Allocate arrays with the specified dimensions: |
| 56 | + allocate(catchind(nlon, nlat), cellarea(nlon, nlat)) |
| 57 | + allocate(lon(nlon), lat(nlat)) |
| 58 | + allocate(loni(nlon), lati(nlat),loni2(nlon), lati2(nlat)) |
| 59 | + allocate(lons(nc_ease),lats(nr_ease)) |
| 60 | + allocate(nsub(nc)) |
| 61 | + |
| 62 | + call formatter%open(trim(pfafData_file), PFIO_READ) |
| 63 | + call formatter%get_var("latitude", lat) |
| 64 | + call formatter%get_var("longitude", lon) |
| 65 | + call formatter%get_var("CatchIndex", catchind) |
| 66 | + call formatter%close() |
| 67 | + |
| 68 | + do i = 1, nc_ease |
| 69 | + call MAPL_ease_inverse( trim(GridName), real(i-1), 0.0, tmp_lat, tmp_lon) |
| 70 | + lons(i) = tmp_lon |
| 71 | + enddo |
| 72 | + do j = 1, nr_ease |
| 73 | + call MAPL_ease_inverse( trim(GridName), 0.0, real(j-1), tmp_lat, tmp_lon) |
| 74 | + lats(j) = tmp_lat |
| 75 | + enddo |
| 76 | + call nearest_index_vector(lat, lats, lati) |
| 77 | + call nearest_index_vector(lon, lons, loni) |
| 78 | + |
| 79 | + call formatter%open(trim(cellarea_file), PFIO_READ) |
| 80 | + call formatter%get_var("data", cellarea) |
| 81 | + call formatter%close() |
| 82 | + cellarea = cellarea / 1.e6 ! Convert cell area (e.g., from m^2 to km^2) |
| 83 | + ! Initialize aggregation arrays to zero: |
| 84 | + allocate(xsub(9999, nc), ysub(9999, nc)) |
| 85 | + nsub = 0 |
| 86 | + ! Loop over all grid cells to aggregate cell areas by catchment and sub-area: |
| 87 | + do xi = 1, nlon |
| 88 | + do yi = 1, nlat |
| 89 | + if (catchind(xi, yi) >= 1) then |
| 90 | + ! The grid cell belongs to a catchment |
| 91 | + id = catchind(xi, yi) ! Get the catchment id for the current cell |
| 92 | + flag = 0 ! Reset flag to indicate whether a matching sub-area is found |
| 93 | + ! If the catchment already has one or more sub-areas, check for a matching sub-area: |
| 94 | + if (nsub(id) >= 1) then |
| 95 | + do i = 1, nsub(id) |
| 96 | + if (loni(xi) == xsub(i, id) .and. lati(yi) == ysub(i, id)) then |
| 97 | + flag = 1 |
| 98 | + exit ! Exit the inner loop since a matching sub-area has been found |
| 99 | + endif |
| 100 | + end do |
| 101 | + endif |
| 102 | + ! If no matching sub-area was found, create a new sub-area: |
| 103 | + if (flag == 0) then |
| 104 | + nsub(id) = nsub(id) + 1 |
| 105 | + xsub(nsub(id), id) = loni(xi) |
| 106 | + ysub(nsub(id), id) = lati(yi) |
| 107 | + endif |
| 108 | + endif |
| 109 | + end do |
| 110 | + end do |
| 111 | + nmax = maxval(nsub) |
| 112 | + !print *,nmax |
| 113 | + deallocate(xsub,ysub) |
| 114 | + allocate(xsub(nmax, nc), ysub(nmax, nc), asub(nmax, nc)) |
| 115 | + ! Initialize aggregation arrays to zero: |
| 116 | + nsub = 0;xsub = 0;ysub = 0;asub = 0. |
| 117 | + ! Loop over all grid cells to aggregate cell areas by catchment and sub-area: |
| 118 | + do xi = 1, nlon |
| 119 | + do yi = 1, nlat |
| 120 | + if (catchind(xi, yi) >= 1) then |
| 121 | + ! The grid cell belongs to a catchment |
| 122 | + id = catchind(xi, yi) ! Get the catchment id for the current cell |
| 123 | + flag = 0 ! Reset flag to indicate whether a matching sub-area is found |
| 124 | + ! If the catchment already has one or more sub-areas, check for a matching sub-area: |
| 125 | + if (nsub(id) >= 1) then |
| 126 | + do i = 1, nsub(id) |
| 127 | + if (loni(xi) == xsub(i, id) .and. lati(yi) == ysub(i, id)) then |
| 128 | + flag = 1 |
| 129 | + ! If a match is found, accumulate the cell area into the existing sub-area: |
| 130 | + asub(i, id) = asub(i, id) + cellarea(xi, yi) |
| 131 | + exit ! Exit the inner loop since a matching sub-area has been found |
| 132 | + endif |
| 133 | + end do |
| 134 | + endif |
| 135 | + ! If no matching sub-area was found, create a new sub-area: |
| 136 | + if (flag == 0) then |
| 137 | + nsub(id) = nsub(id) + 1 |
| 138 | + xsub(nsub(id), id) = loni(xi) |
| 139 | + ysub(nsub(id), id) = lati(yi) |
| 140 | + asub(nsub(id), id) = cellarea(xi, yi) |
| 141 | + endif |
| 142 | + endif |
| 143 | + end do |
| 144 | + end do |
| 145 | + |
| 146 | + ! Open the catchment definition file for the M36 grid and read the total number of catchments (header) |
| 147 | + open(77, file="clsm/catchment.def");read(77, *) ntot |
| 148 | + ! Allocate arrays with size nt |
| 149 | + allocate(tid(ntot), catid(ntot), lon_left(ntot), lon_right(ntot), lat_bottom(ntot), lat_top(ntot),latc(ntot),lonc(ntot)) |
| 150 | + allocate(lati_tile(ntot),loni_tile(ntot),map_tile(nc_ease,nr_ease)) |
| 151 | + ! Loop over each catchment and read: id, catchment id, left/right longitudes, bottom/top latitudes |
| 152 | + do i = 1, ntot |
| 153 | + read(77, *) tid(i), catid(i), lon_left(i), lon_right(i), lat_bottom(i), lat_top(i) |
| 154 | + end do |
| 155 | + latc = (lat_bottom + lat_top) / 2. |
| 156 | + lonc = (lon_left + lon_right) / 2. |
| 157 | + call nearest_index_vector(latc,lats,lati_tile) |
| 158 | + call nearest_index_vector(lonc,lons,loni_tile) |
| 159 | + map_tile=-9999 |
| 160 | + do i =1, ntot |
| 161 | + map_tile(loni_tile(i),lati_tile(i)) = i |
| 162 | + enddo |
| 163 | + |
| 164 | + allocate(isub(nmax, nc)) |
| 165 | + isub=0 |
| 166 | + ! Loop over each catchment |
| 167 | + do i = 1, nc |
| 168 | + ! Loop over each potential sub-area within the current catchment |
| 169 | + do j = 1, nmax |
| 170 | + xi = xsub(j, i) ! Retrieve the x-coordinate for the sub-area |
| 171 | + yi = ysub(j, i) ! Retrieve the y-coordinate for the sub-area |
| 172 | + if (xi /= 0) then ! Check if a valid sub-area exists (non-zero x-coordinate) |
| 173 | + isub(j, i) = map_tile(xi, yi) ! Map the sub-area coordinates to a global tile index using map_tile |
| 174 | + endif |
| 175 | + enddo |
| 176 | + enddo |
| 177 | + |
| 178 | + allocate(area_cat(nc),frac(nmax,nc),nsub_tile(ntot),flag2(nmax,nc)) |
| 179 | + where(isub==-9999) asub=0. |
| 180 | + area_cat=0. |
| 181 | + do i=1,nc |
| 182 | + area_cat(i)=sum(asub(:,i)) |
| 183 | + enddo |
| 184 | + nsub_tile=0 |
| 185 | + frac=0. |
| 186 | + do i=1,nc |
| 187 | + do j=1,nmax |
| 188 | + if(isub(j,i)>0)then |
| 189 | + it=isub(j,i) |
| 190 | + nsub_tile(it)=nsub_tile(it)+1 |
| 191 | + frac(j,i)=asub(j,i)/area_cat(i) |
| 192 | + endif |
| 193 | + if(isub(j,i)==0)exit |
| 194 | + enddo |
| 195 | + enddo |
| 196 | + nmax2=maxval(nsub_tile) |
| 197 | + allocate(csub(nmax2,ntot),frac_tile(nmax2,ntot)) |
| 198 | + csub=0 |
| 199 | + nsub_tile=0 |
| 200 | + frac_tile=0. |
| 201 | + do i=1,nc |
| 202 | + do j=1,nmax |
| 203 | + if(isub(j,i)>0)then |
| 204 | + it=isub(j,i) |
| 205 | + nsub_tile(it)=nsub_tile(it)+1 |
| 206 | + csub(nsub_tile(it),it)=i |
| 207 | + frac_tile(nsub_tile(it),it)=frac(j,i) |
| 208 | + endif |
| 209 | + if(isub(j,i)==0)exit |
| 210 | + enddo |
| 211 | + enddo |
| 212 | + ns_tot=sum(nsub_tile) |
| 213 | + allocate(tile_id(ns_tot), pfaf_index(ns_tot), pfaf_frac(ns_tot)) |
| 214 | + it = 0 |
| 215 | + do i=1,ntot |
| 216 | + do j=1,nmax2 |
| 217 | + if(csub(j,i)>0)then |
| 218 | + it = it+1 |
| 219 | + tile_id(it) = i |
| 220 | + pfaf_index(it) = csub(j,i) |
| 221 | + pfaf_frac(it) = frac_tile(j,i) |
| 222 | + endif |
| 223 | + if(csub(j,i)==0)exit |
| 224 | + enddo |
| 225 | + enddo |
| 226 | + |
| 227 | + call meta%add_dimension('tile', ns_tot) |
| 228 | + |
| 229 | + v = Variable(type=PFIO_INT32, dimensions='tile') |
| 230 | + call v%add_attribute('units', '1') |
| 231 | + call v%add_attribute('long_name', 'tile_id') |
| 232 | + call meta%add_variable('tile_id', v) |
| 233 | + |
| 234 | + v = Variable(type=pFio_INT32, dimensions='tile') |
| 235 | + call v%add_attribute('units', '1') |
| 236 | + call v%add_attribute('long_name', 'pfaf_index') |
| 237 | + call meta%add_variable('pfaf_index', v) |
| 238 | + |
| 239 | + v = Variable(type=pFio_REAL32, dimensions='tile') |
| 240 | + call v%add_attribute('units', '1') |
| 241 | + call v%add_attribute('long_name', 'area_fraction_of_catchment') |
| 242 | + call meta%add_variable('pfaf_frac', v) |
| 243 | + |
| 244 | + call formatter%create(file_out, mode=PFIO_CLOBBER) |
| 245 | + call formatter%write(meta) |
| 246 | + call formatter%put_var('tile_id', tile_id) |
| 247 | + call formatter%put_var('pfaf_index', pfaf_index) |
| 248 | + call formatter%put_var('pfaf_frac', pfaf_frac) |
| 249 | + call formatter%close() |
| 250 | + |
| 251 | + end subroutine get_Pfaf_frac |
| 252 | + |
| 253 | + subroutine nearest_index_vector(candidates, targets, idx) |
| 254 | + ! For each targets(k), find argmin_j |candidates(j) - targets(k)| |
| 255 | + real*8, intent(in) :: targets(:) |
| 256 | + real*8, intent(in) :: candidates(:) |
| 257 | + integer, intent(out) :: idx(size(candidates)) ! 1-based indices |
| 258 | + integer :: k, j, nT, nC, best_j |
| 259 | + real*8 :: best_d, d |
| 260 | + |
| 261 | + nT = size(targets) |
| 262 | + nC = size(candidates) |
| 263 | + |
| 264 | + do k = 1, nC |
| 265 | + best_d = huge(1.0d0) |
| 266 | + best_j = 1 |
| 267 | + do j = 1, nT |
| 268 | + d = abs(candidates(k) - targets(j)) |
| 269 | + if (d < best_d) then |
| 270 | + best_d = d |
| 271 | + best_j = j |
| 272 | + end if |
| 273 | + end do |
| 274 | + idx(k) = best_j ! already 1-based |
| 275 | + end do |
| 276 | + end subroutine nearest_index_vector |
| 277 | + |
| 278 | +end module pfaf_fracMod |
0 commit comments