Skip to content

Commit 4c94e7e

Browse files
authored
Merge pull request #1028 from GEOS-ESM/feature/wjiang/nc4_tilefile
add nc4-formatted tile file when generating bcs
2 parents 64abc38 + 8c1d0fa commit 4c94e7e

24 files changed

+12080
-12986
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ ecbuild_add_executable (TARGET mkMOMAquaRaster.x SOURCES mkMOMAquaRaster.F90 LIB
4848
ecbuild_add_executable (TARGET FillMomGrid.x SOURCES FillMomGrid.F90 LIBS MAPL ${this})
4949
ecbuild_add_executable (TARGET mk_runofftbl.x SOURCES mk_runofftbl.F90 LIBS MAPL ${this})
5050
ecbuild_add_executable (TARGET mkEASETilesParam.x SOURCES mkEASETilesParam.F90 LIBS MAPL ${this})
51+
ecbuild_add_executable (TARGET TileFile_ASCII_to_nc4.x SOURCES TileFile_ASCII_to_nc4.F90 LIBS MAPL ${this})
5152

5253
install(PROGRAMS clsm_plots.pro create_README.csh DESTINATION bin)
5354
file(GLOB MAKE_BCS_PYTHON CONFIGURE_DEPENDS "./make_bcs*.py")
5455
list(FILTER MAKE_BCS_PYTHON EXCLUDE REGEX "make_bcs_shared.py")
55-
install(PROGRAMS ${MAKE_BCS_PYTHON} DESTINATION bin)
56+
install(PROGRAMS ${MAKE_BCS_PYTHON} DESTINATION bin)
57+
install(PROGRAMS TileFile_ASCII_to_nc4.py DESTINATION bin)
5658

5759
set(file ./make_bcs_shared.py)
5860
configure_file(${file} ${file} @ONLY)

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
program mkOverlaySimple
55

6-
use LogRectRasterizeMod
6+
use LogRectRasterizeMod, ONLY: WriteRaster, WriteTiling, SortTiling
77
use MAPL_SortMod
88
use MAPL_HashMod
99
use MAPL_ExceptionHandling
@@ -28,7 +28,7 @@ program mkOverlaySimple
2828
integer, parameter :: TILUNIT1 = 22
2929
integer, parameter :: TILUNIT2 = 23
3030

31-
real(kind=8), parameter :: PI = MAPL_PI_R8
31+
real(REAL64), parameter :: PI = MAPL_PI_R8
3232

3333
integer :: command_argument_count
3434
integer :: nxt, argl, fill
@@ -43,12 +43,12 @@ program mkOverlaySimple
4343
integer, allocatable :: RST2(: )
4444
integer, allocatable :: iTable(:,:)
4545

46-
real(kind=8) , allocatable :: Table1(:,:)
47-
real(kind=8) , allocatable :: Table2(:,:)
48-
real(kind=8) , allocatable :: rTable(:,:)
49-
real(kind=8) , allocatable :: cc(:), ss(:)
50-
real(kind=8) :: dx, dy, area, xc, yc, d2r, vv(4)
51-
real(kind=8) :: lats, lons, da
46+
real(REAL64) , allocatable :: Table1(:,:)
47+
real(REAL64) , allocatable :: Table2(:,:)
48+
real(REAL64) , allocatable :: rTable(:,:)
49+
real(REAL64) , allocatable :: cc(:), ss(:)
50+
real(REAL64) :: dx, dy, area, xc, yc, d2r, vv(4)
51+
real(REAL64) :: lats, lons, da
5252

5353
logical :: DoZip
5454
logical :: Verb

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
module CubedSphere_GridMod
33
use MAPL_ConstantsMod
44

5-
#define r8 kind=8
5+
#define r8 REAL64
66

77
implicit none
88

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
program FillMomGrid
66

7-
use LogRectRasterizeMod
7+
use LogRectRasterizeMod, ONLY: WriteRaster, WriteTiling
88
use MAPL_SortMod
99
use MAPL_HashMod
1010
use MAPL_ConstantsMod
11+
1112
use, intrinsic :: iso_fortran_env, only: REAL64
1213

1314
! Modifies Pfafstetter.rst such that for every pixel within a MOM ocean
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
!
2+
! Utility program that converts ASCII-formatted *.til file and catchment.def file into a single nc4 file
3+
!
4+
! Usage TileFile_ASCII-to-nc4.x tile_file catchmentdef_file
5+
!
6+
! wjiang, rreichle, 29 Nov 2024
7+
8+
program TileFile_ASCII_to_nc4
9+
use, intrinsic :: iso_fortran_env, only: REAL64
10+
use MAPL
11+
use LogRectRasterizeMod, only: WriteTilingNC4, MAPL_UNDEF_R8
12+
use EASE_conv, only: ease_extent
13+
14+
implicit none
15+
16+
character(512) :: arg
17+
integer :: i, unit, unit2
18+
19+
character(:), allocatable :: tile_file
20+
character(:), allocatable :: catchmentdef_file
21+
real(REAL64), allocatable :: rTable(:,:)
22+
integer, allocatable :: iTable(:,:)
23+
character(128) :: gName1, gName2
24+
character(len=512) :: tmpline
25+
26+
character(:), allocatable :: array(:)
27+
character(len=:), allocatable :: filenameNC4
28+
29+
real :: cell_area
30+
31+
integer :: n_tile, n_grid, n_lon1, n_lat1, n_cat, tmp_in1, tmp_in2
32+
integer :: n_lon2, n_lat2, nx, ny, num, ll, maxcat
33+
logical :: file_exists
34+
35+
! ----------------------------------------------------------------------
36+
!
37+
! process command-line arguments
38+
39+
CALL get_command_argument(1, arg)
40+
tile_file = trim(arg)
41+
CALL get_command_argument(2, arg)
42+
catchmentdef_file = trim(arg)
43+
44+
! ----------------------------------------------------------------------
45+
!
46+
! open and read *.til ASCII file
47+
48+
open (newunit=unit, file=trim(tile_file), form='formatted', action='read')
49+
50+
read (unit,*) tmpline ! header line 1: N_tile [maxcat] nx ny (see below)
51+
read (unit,*) N_grid ! header line 2: N_grid [=1 for EASE, =2 otherwise]
52+
read (unit,*) gName1 ! header line 3: name of atm grid
53+
read (unit,*) n_lon1 ! header line 4: N_lon of atm grid
54+
read (unit,*) n_lat1 ! header line 5: N_lat of atm grid
55+
56+
! special treatment needed for header line 1 because maxcat is not included in legacy bcs
57+
58+
call split(tmpline, array, " ")
59+
read(array(1), *) n_tile
60+
num = size(array)
61+
ll = 0
62+
if (num == 4) then
63+
ll = 1
64+
read(array(2), *) maxcat ! number of Pfafstetter catchments
65+
else
66+
maxcat = -1 ! maxcat not available in legacy bcs
67+
endif
68+
69+
read(array(2+ll), *) nx ! N_lon of raster grid
70+
read(array(3+ll), *) ny ! N_lat of raster grid
71+
72+
if (N_grid == 1) then
73+
74+
! EASE grid tile space
75+
76+
! in some legacy bcs, dummy ocean grid info is included in header (despite N_grid=1);
77+
! read next line and decide if it is dummy header or info for first tile
78+
79+
read (unit,*) tmpline
80+
if (index(tmpline,'OCEAN')/=0) then
81+
read (unit,*)
82+
read (unit,*)
83+
read (unit,*) tmpline
84+
endif
85+
86+
else
87+
88+
! lat/lon or cube-sphere tile space
89+
90+
read (unit,*) gName2
91+
read (unit,*) n_lon2
92+
read (unit,*) n_lat2
93+
read (unit,*) tmpline ! read info for first tile (to accommodate legacy EASE grid issues above)
94+
95+
endif
96+
97+
allocate(iTable(N_tile,0:7))
98+
allocate(rTable(N_tile,10))
99+
100+
rTable = MAPL_UNDEF_r8
101+
102+
! read ASCII tile file (NOTE: Info for first tile is already in tmpline!)
103+
104+
if ( index(gName1, 'EASE') /=0 ) then ! EASE grid tile space
105+
106+
read (tmpline,*) iTable(1,0), iTable(1,4), rTable(1,1), rTable(1,2), &
107+
iTable(1,2), iTable(1,3), rTable(1,4)
108+
109+
do i = 2, N_tile
110+
read (unit,*) iTable(i,0), iTable(i,4), rTable(i,1), rTable(i,2), &
111+
iTable(i,2), iTable(i,3), rTable(i,4)
112+
enddo
113+
114+
! rTable(:,4) is tile area fraction within grid cell (fr), convert to area;
115+
! get fr back in WriteTilingNC4
116+
117+
call ease_extent(gName1, tmp_in1, tmp_in2, cell_area=cell_area) ! get EASE grid cell area
118+
119+
rTable(:,3) = rTable(:,4)*cell_area
120+
rTable(:,4) = cell_area
121+
122+
else ! lat/lon or cube-sphere tile space
123+
124+
read (tmpline,*) iTable(1,0), rTable(1,3), rTable(1,1), rTable(1,2), &
125+
iTable(1,2), iTable(1,3), rTable(1,4), iTable(1,6), &
126+
iTable(1,4), iTable(1,5), rTable(1,5), iTable(1,7)
127+
128+
do i = 2, N_tile
129+
read (unit,*) iTable(i,0), rTable(i,3), rTable(i,1), rTable(i,2), &
130+
iTable(i,2), iTable(i,3), rTable(i,4), iTable(i,6), &
131+
iTable(i,4), iTable(i,5), rTable(i,5), iTable(i,7)
132+
enddo
133+
134+
! re-define rTable(:,4) and rTable(:,5).
135+
! fr will be re-created in WriteTilingNC4
136+
137+
where (rTable(:,4) /=0.0)
138+
rTable(:,4) = rTable(:,3)/rTable(:,4)
139+
endwhere
140+
141+
where (rTable(:,5) /=0.0)
142+
rTable(:,5) = rTable(:,3)/rTable(:,5)
143+
endwhere
144+
145+
endif
146+
147+
close(unit)
148+
149+
! ----------------------------------------------------------------------
150+
!
151+
! open and read catchment.def ASCII file
152+
153+
inquire( file= trim(catchmentdef_file), exist=file_exists)
154+
155+
if (file_exists) then
156+
157+
open (newunit=unit, file=trim(catchmentdef_file), form='formatted', action='read')
158+
159+
read(unit, *) n_cat ! number of *land* tiles
160+
161+
do i = 1, n_cat
162+
read(unit, *) &
163+
tmp_in1, &
164+
tmp_in2, &
165+
rTable(i, 6), &
166+
rTable(i, 7), &
167+
rTable(i, 8), &
168+
rTable(i, 9), &
169+
rTable(i,10)
170+
enddo
171+
172+
close(unit)
173+
174+
endif
175+
176+
! assemble name of nc4 file
177+
178+
ll = index(tile_file, '.til')
179+
filenameNC4 = tile_file(1:ll)//'nc4'
180+
181+
! write nc4 file
182+
183+
if (N_grid == 1) then
184+
call WriteTilingNC4(filenameNc4, [gName1 ], [n_lon1 ], [n_lat1 ], nx, ny, iTable, rTable, N_PfafCat=maxcat)
185+
else
186+
call WriteTilingNC4(filenameNc4, [gName1, gName2], [n_lon1, n_lon2], [n_lat1, n_lat2], nx, ny, iTable, rTable, N_PfafCat=maxcat)
187+
endif
188+
189+
contains
190+
191+
subroutine split(input_line,array,delimiters,order,nulls)
192+
193+
character(len=*),intent(in) :: input_line
194+
character(len=*),optional,intent(in) :: delimiters
195+
character(len=*),optional,intent(in) :: order
196+
character(len=*),optional,intent(in) :: nulls
197+
character(len=:),allocatable,intent(out) :: array(:)
198+
199+
integer :: n
200+
integer,allocatable :: ibegin(:)
201+
integer,allocatable :: iterm(:)
202+
character(len=:),allocatable :: dlim
203+
character(len=:),allocatable :: ordr
204+
character(len=:),allocatable :: nlls
205+
integer :: ii,iiii
206+
integer :: icount
207+
integer :: ilen
208+
integer :: i10,i20,i30
209+
integer :: icol
210+
integer :: idlim
211+
integer :: ifound
212+
integer :: inotnull
213+
integer :: ireturn
214+
integer :: imax
215+
216+
! decide on value for optional DELIMITERS parameter
217+
if (present(delimiters)) then ! optional delimiter list was present
218+
if(delimiters/='')then ! if DELIMITERS was specified and not null use it
219+
dlim=delimiters
220+
else ! DELIMITERS was specified on call as empty string
221+
dlim=' '//char(9)//char(10)//char(11)//char(12)//char(13)//char(0) ! use default delimiter when not specified
222+
endif
223+
else ! no delimiter value was specified
224+
dlim=' '//char(9)//char(10)//char(11)//char(12)//char(13)//char(0) ! use default delimiter when not specified
225+
endif
226+
idlim=len(dlim) ! dlim a lot of blanks on some machines if dlim is a big string
227+
228+
if(present(order))then; ordr=adjustl(order); else; ordr='sequential'; endif ! decide on value for optional ORDER parameter
229+
230+
if(present(nulls))then; nlls=adjustl(nulls); else; nlls='ignore' ; endif ! optional parameter
231+
232+
n=len(input_line)+1 ! max number of strings INPUT_LINE could split into if all delimiter
233+
allocate(ibegin(n)) ! allocate enough space to hold starting location of tokens if string all tokens
234+
allocate(iterm(n)) ! allocate enough space to hold ending location of tokens if string all tokens
235+
ibegin(:)=1
236+
iterm(:)=1
237+
238+
ilen=len(input_line) ! ILEN is the column position of the last non-blank character
239+
icount=0 ! how many tokens found
240+
inotnull=0 ! how many tokens found not composed of delimiters
241+
imax=0 ! length of longest token found
242+
243+
select case (ilen)
244+
245+
case (0) ! command was totally blank
246+
247+
case default ! there is at least one non-delimiter in INPUT_LINE if get here
248+
icol=1 ! initialize pointer into input line
249+
INFINITE: do i30=1,ilen,1 ! store into each array element
250+
ibegin(i30)=icol ! assume start new token on the character
251+
if(index(dlim(1:idlim),input_line(icol:icol))==0)then ! if current character is not a delimiter
252+
iterm(i30)=ilen ! initially assume no more tokens
253+
do i10=1,idlim ! search for next delimiter
254+
ifound=index(input_line(ibegin(i30):ilen),dlim(i10:i10))
255+
IF(ifound>0)then
256+
iterm(i30)=min(iterm(i30),ifound+ibegin(i30)-2)
257+
endif
258+
enddo
259+
icol=iterm(i30)+2 ! next place to look as found end of this token
260+
inotnull=inotnull+1 ! increment count of number of tokens not composed of delimiters
261+
else ! character is a delimiter for a null string
262+
iterm(i30)=icol-1 ! record assumed end of string. Will be less than beginning
263+
icol=icol+1 ! advance pointer into input string
264+
endif
265+
imax=max(imax,iterm(i30)-ibegin(i30)+1)
266+
icount=i30 ! increment count of number of tokens found
267+
if(icol>ilen)then ! no text left
268+
exit INFINITE
269+
endif
270+
enddo INFINITE
271+
272+
end select
273+
274+
select case (trim(adjustl(nlls)))
275+
case ('ignore','','ignoreend')
276+
ireturn=inotnull
277+
case default
278+
ireturn=icount
279+
end select
280+
allocate(character(len=imax) :: array(ireturn)) ! allocate the array to return
281+
!allocate(array(ireturn)) ! allocate the array to turn
282+
283+
select case (trim(adjustl(ordr))) ! decide which order to store tokens
284+
case ('reverse','right') ; ii=ireturn ; iiii=-1 ! last to first
285+
case default ; ii=1 ; iiii=1 ! first to last
286+
end select
287+
288+
do i20=1,icount ! fill the array with the tokens that were found
289+
if(iterm(i20)<ibegin(i20))then
290+
select case (trim(adjustl(nlls)))
291+
case ('ignore','','ignoreend')
292+
case default
293+
array(ii)=' '
294+
ii=ii+iiii
295+
end select
296+
else
297+
array(ii)=input_line(ibegin(i20):iterm(i20))
298+
ii=ii+iiii
299+
endif
300+
enddo
301+
end subroutine split
302+
303+
end program
304+
305+
! ======================= EOF ====================================================

0 commit comments

Comments
 (0)