Skip to content

Commit 06bfaf0

Browse files
Merge pull request #1158 from GEOS-ESM/feature/wjiang/river_bcs
create bcs for river-routing
2 parents 1840281 + 54008e6 commit 06bfaf0

File tree

4 files changed

+287
-5
lines changed

4 files changed

+287
-5
lines changed

GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSsurface_GridComp/Utils/Raster/makebcs/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ rasterize.F90
77
read_riveroutlet.F90
88
CubedSphere_GridMod.F90
99
rmTinyCatchParaMod.F90
10+
pfaf_frac.F90
1011
zip.c
1112
util.c
1213
)

GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSsurface_GridComp/Utils/Raster/makebcs/make_bcs_shared.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def get_script_mv(grid_type):
9292
/bin/mv {GRIDNAME}.j geometry/{GRIDNAME}/.
9393
/bin/cp til/{GRIDNAME}{RS}.til geometry/{GRIDNAME}/.
9494
/bin/cp til/{GRIDNAME}{RS}.nc4 geometry/{GRIDNAME}/.
95+
/bin/cp til/{GRIDNAME}_tile_pfaf.nc4 geometry/{GRIDNAME}/.
9596
if( {TRIPOL_OCEAN} == True ) /bin/cp til/{GRIDNAME}{RS}.TRN geometry/{GRIDNAME}/.
9697
9798
/bin/mv rst til geometry/{GRIDNAME}/.
@@ -172,14 +173,13 @@ def get_script_mv(grid_type):
172173
echo "Successfully copied CO2_MonthlyMean_DiurnalCycle.nc4 to bcs dir."
173174
endif
174175
175-
if(-d land/shared/river_input) then
176-
echo "river_input already present in bcs dir."
176+
if(-f land/shared/river_input.nc ) then
177+
echo "river_input.nc already present in bcs dir."
177178
else
178-
/bin/cp -rp /discover/nobackup/yzeng3/data/river_input land/shared/river_input
179-
echo "Successfully copied river_input to bcs dir."
179+
/bin/cp -p /discover/nobackup/projects/gmao/bcs_shared/test/stuff/route_model/v1/river_input.nc land/shared/river_input.nc
180+
echo "Successfully copied river_input.nc to bcs dir."
180181
endif
181182
182-
183183
# adjust permissions
184184
185185
chmod +rX -R geometry land logs

GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSsurface_GridComp/Utils/Raster/makebcs/mkEASETilesParam.F90

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ PROGRAM mkEASETilesParam
3939
use MAPL_ConstantsMod, only : MAPL_PI_r8, MAPL_RADIUS
4040
use MAPL_ExceptionHandling
4141
use MAPL, only : MAPL_ease_extent, MAPL_ease_convert, MAPL_ease_inverse, MAPL_WriteTilingNC4
42+
use pfaf_fracMod, only : get_pfaf_frac
4243
use netcdf
4344

4445
implicit none
@@ -979,6 +980,8 @@ PROGRAM mkEASETilesParam
979980

980981
deallocate( tileid_index, catid_index,veg )
981982
deallocate( tile_area, ease_grid_area, tile_elev, my_land, all_id )
983+
984+
call get_pfaf_frac('til/'//trim(EASELabel)//'_tile_pfaf.nc4', EASELabel)
982985

983986
! Commented out "empty" if-block. -rreichle, 15 Jun 2023
984987
!
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
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

Comments
 (0)