orog_mask_tools  1.13.0
inland.F90
Go to the documentation of this file.
1 
4 
9 PROGRAM inland_mask
10  USE cs_nb
11  IMPLICIT NONE
12 
13  INTEGER :: tile, i, j
14  TYPE(nb_gp_idx) :: nbs
15 
16  REAL, ALLOCATABLE :: inland(:,:,:)
17  REAL, ALLOCATABLE :: land_frac(:,:,:)
18  INTEGER :: tile_beg, tile_end
19  INTEGER :: cs_res, x_res, y_res
20  CHARACTER(len=32) :: arg
21  INTEGER :: stat
22  INTEGER :: max_rd
23  REAL :: cutoff
24  CHARACTER(len=1) :: reg
25 
26  LOGICAL, ALLOCATABLE :: done(:,:,:)
27 
28  CALL getarg(0, arg) ! get the program name
29  IF (iargc() /= 3 .AND. iargc() /= 4) THEN
30  print*, 'Usage: '
31  print*, trim(arg), ' [cres(48,96, ...)][nonland cutoff][max recursive depth][regional(r),global(g)]'
32  stop
33  ENDIF
34 
35  CALL getarg(1, arg)
36  READ(arg,*,iostat=stat) cs_res
37  CALL getarg(2, arg)
38  READ(arg,*,iostat=stat) cutoff
39  CALL getarg(3, arg)
40  READ(arg,*,iostat=stat) max_rd
41  CALL getarg(4, reg)
42 
43  IF (reg /= 'r') THEN
44  tile_beg = 1; tile_end = 6
45 ! read in orography data (land_frac)
46  CALL read_orog(cs_res)
47 
48 ! init inter-panel neighbor index
49  CALL idx_init(cs_res)
50 
51 ! create a inland mask
52  CALL mark_global_inland(cs_res)
53 
54 ! write back to the orography data files
55  CALL write_inland(cs_res)
56  ELSE
57 ! read in orography data (land_frac) for the SAR domain
58  CALL read_orog_reg(cs_res)
59 
60 ! init inter-panel neighbor index
61  CALL idx_init_reg(x_res, y_res)
62 
63 ! create a inland mask
64  CALL mark_inland_reg(cs_res)
65 
66 ! write back to the orography data files
67  CALL write_inland_reg(cs_res)
68  ENDIF
69 
70  CALL free_mem()
71 
72 CONTAINS
73 
79 SUBROUTINE mark_global_inland(cs_res)
80  INTEGER, INTENT(IN) :: cs_res
81  INTEGER :: i_seed, j_seed
82 
83  ALLOCATE(done(cs_res,cs_res,6))
84  ALLOCATE(inland(cs_res,cs_res,6))
85  done = .false.
86  inland = 1.0
87 
88  i_seed = cs_res/2; j_seed = cs_res/2
89  CALL mark_global_inland_rec_d(i_seed, j_seed, 2, 0)
90 
91 ! to make sure black sea is excluded
92  i_seed = REAL(cs_res)/32.0*3; j_seed = i_seed
93  CALL mark_global_inland_rec_d(i_seed, j_seed, 3, 0)
94 
95  DEALLOCATE(done)
96 
97 END SUBROUTINE mark_global_inland
98 
104 SUBROUTINE mark_inland_reg(cs_res)
105  INTEGER, INTENT(IN) :: cs_res
106  INTEGER :: i_seed, j_seed
107  INTEGER :: i
108 
109  ALLOCATE(done(x_res,y_res,1))
110  ALLOCATE(inland(x_res,y_res,1))
111 
112  done = .false.
113  inland = 1.0
114 
115 ! set up three seeds, for the current domain
116  i_seed = 1; j_seed = y_res/2
117  CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
118 
119  i_seed = x_res; j_seed = y_res/2
120  CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
121 
122  i_seed = x_res/3; j_seed = 1
123  CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
124 
125  j_seed = 1
126  DO i = 1, x_res
127  CALL mark_regional_inland_rec_d(i, j_seed, 1, 0)
128  ENDDO
129 
130  j_seed = y_res
131  DO i = x_res/2, x_res
132  CALL mark_regional_inland_rec_d(i, j_seed, 1, 0)
133  ENDDO
134 
135 ! set up additional 3 seeds for ESG CONUS grid
136 ! i_seed = 1600; j_seed = 1040
137 ! i_seed = x_res - 10; j_seed = y_res
138 ! CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
139 
140 ! i_seed = x_res - 60; j_seed = y_res
141 ! CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
142 
143 ! i_seed = x_res - 275; j_seed = y_res
144 ! CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
145 
146 ! i_seed = 500; j_seed = 1
147 ! CALL mark_regional_inland_rec_d(i_seed, j_seed, 1, 0)
148 
149  DEALLOCATE(done)
150 
151 END SUBROUTINE mark_inland_reg
152 
161 RECURSIVE SUBROUTINE mark_global_inland_rec_d(i, j, t, rd)
162  INTEGER, INTENT(IN) :: i, j, t, rd
163 
164  TYPE(nb_gp_idx) :: nbs
165  INTEGER :: k, nrd
166 
167  IF (t == 0) RETURN
168 
169  IF (land_frac(i,j,t) <= 0.15) THEN
170  nrd = 1
171  ELSE
172  nrd = rd + 1
173  ENDIF
174 
175  IF (nrd > max_rd) RETURN
176 
177  IF (done(i,j,t)) RETURN
178  IF (land_frac(i,j,t) < cutoff) THEN
179  done(i,j,t) = .true.
180  inland(i,j,t) = 0.0
181  CALL neighbors(t, i, j, nbs)
182  ! recursively go through k neighbors
183  DO k = 1, 4
184  CALL mark_global_inland_rec_d(nbs%ijt(1,k),nbs%ijt(2,k),nbs%ijt(3,k),nrd)
185  ENDDO
186  ENDIF
187 
188 END SUBROUTINE mark_global_inland_rec_d
189 
198 RECURSIVE SUBROUTINE mark_regional_inland_rec_d(i, j, t, rd)
199  INTEGER, INTENT(IN) :: i, j, t, rd
200 
201  TYPE(nb_gp_idx) :: nbs
202  INTEGER :: k, nrd
203 
204  IF (t == 0) RETURN
205 
206  IF (land_frac(i,j,t) <= 0.15) THEN
207  nrd = 1
208  ELSE
209  nrd = rd + 1
210  ENDIF
211 
212  IF (nrd > max_rd) RETURN
213 
214  IF (done(i,j,t)) RETURN
215  IF (land_frac(i,j,t) < cutoff) THEN
216  done(i,j,t) = .true.
217  inland(i,j,t) = 0.0
218  CALL neighbors_reg(i, j, nbs)
219  ! recursively go through k neighbors
220  DO k = 1, 4
221  CALL mark_regional_inland_rec_d(nbs%ijt(1,k),nbs%ijt(2,k),nbs%ijt(3,k),nrd)
222  ENDDO
223  ENDIF
224 
225 END SUBROUTINE mark_regional_inland_rec_d
226 
232 SUBROUTINE read_orog(cs_res)
233  USE netcdf
234  INTEGER, INTENT(IN) :: cs_res
235 
236  INTEGER :: tile_sz, tile_num
237  INTEGER :: stat, ncid, varid
238  INTEGER :: land_frac_id, slmsk_id, geolon_id, geolat_id
239  CHARACTER(len=256) :: filename,string
240  CHARACTER(len=1) :: ich
241  CHARACTER(len=4) res_ch
242  CHARACTER(len=8) dimname
243 
244  INTEGER :: i, j
245  REAL, ALLOCATABLE :: var_tmp(:,:)
246 
247  ALLOCATE(var_tmp(cs_res,cs_res))
248  ALLOCATE(land_frac(cs_res,cs_res,6))
249 
250  WRITE(res_ch,'(I4)') cs_res
251  DO tile_num = tile_beg, tile_end
252  WRITE(ich, '(I1)') tile_num
253  filename = "oro.C" // trim(adjustl(res_ch)) // ".tile" // ich // ".nc"
254  print *,'Read, update, and write ',trim(filename)
255  stat = nf90_open(filename, nf90_nowrite, ncid)
256  CALL nc_opchk(stat, "nf90_open oro_data.nc")
257 
258 ! original orodata netcdf file uses (y, x) order, so we made change to match it.
259  stat = nf90_inq_varid(ncid, "land_frac", land_frac_id)
260  CALL nc_opchk(stat, "nf90_inq_varid: land_frac")
261  stat = nf90_get_var(ncid, land_frac_id, var_tmp, &
262  start = (/ 1, 1 /), count = (/ cs_res, cs_res /) )
263  CALL nc_opchk(stat, "nf90_get_var: land_frac")
264  land_frac(:,:,tile_num) = var_tmp(:,:)
265  stat = nf90_close(ncid)
266  CALL nc_opchk(stat, "nf90_close oro_data.nc")
267  ENDDO
268 
269  DEALLOCATE(var_tmp)
270 
271 END SUBROUTINE read_orog
272 
278 SUBROUTINE read_orog_reg(cs_res)
279  USE netcdf
280  INTEGER, INTENT(IN) :: cs_res
281 
282  INTEGER :: tile_num
283  INTEGER :: stat, ncid, x_dimid, y_dimid, varid
284  INTEGER :: land_frac_id, slmsk_id, geolon_id, geolat_id
285  CHARACTER(len=256) :: filename,string
286  CHARACTER(len=1) :: ich
287  CHARACTER(len=4) res_ch
288  CHARACTER(len=8) dimname
289 
290  INTEGER :: i, j
291  REAL, ALLOCATABLE :: var_tmp(:,:)
292 
293  WRITE(res_ch,'(I4)') cs_res
294  tile_num = 7
295  WRITE(ich, '(I1)') tile_num
296  filename = "oro.C" // trim(adjustl(res_ch)) // ".tile" // ich // ".nc"
297  print *,'Read, update, and write ',trim(filename)
298  stat = nf90_open(filename, nf90_nowrite, ncid)
299  CALL nc_opchk(stat, "nf90_open oro_data.nc")
300  stat = nf90_inq_dimid(ncid, "lon", x_dimid)
301  CALL nc_opchk(stat, "nf90_inq_dim: x")
302  stat = nf90_inq_dimid(ncid, "lat", y_dimid)
303  CALL nc_opchk(stat, "nf90_inq_dim: y")
304  stat = nf90_inquire_dimension(ncid,x_dimid,dimname,len=x_res)
305  CALL nc_opchk(stat,'nf90_inquire_dimension: lon')
306  stat = nf90_inquire_dimension(ncid,y_dimid,dimname,len=y_res)
307  CALL nc_opchk(stat,'nf90_inquire_dimension: lon')
308 
309 ! original orodata netcdf file uses (y, x) order, so we made change to match it.
310  ALLOCATE(var_tmp(x_res,y_res))
311  ALLOCATE(land_frac(x_res,y_res,1))
312  stat = nf90_inq_varid(ncid, "land_frac", land_frac_id)
313  CALL nc_opchk(stat, "nf90_inq_varid: land_frac")
314  stat = nf90_get_var(ncid, land_frac_id, var_tmp, &
315  start = (/ 1, 1 /), count = (/ x_res, y_res /) )
316  CALL nc_opchk(stat, "nf90_get_var: land_frac")
317  land_frac(:,:,1) = var_tmp(:,:)
318  stat = nf90_close(ncid)
319  CALL nc_opchk(stat, "nf90_close oro_data.nc")
320 
321  DEALLOCATE(var_tmp)
322 
323 END SUBROUTINE read_orog_reg
324 
330 SUBROUTINE write_inland(cs_res)
331  USE netcdf
332  INTEGER, INTENT(IN) :: cs_res
333 
334  CHARACTER(len=256) :: filename
335  CHARACTER(len=1) :: ich
336  CHARACTER(len=4) res_ch
337 
338  INTEGER :: tile_num
339  INTEGER :: stat, ncid, x_dimid, y_dimid, inland_id, dimids(2)
340  REAL, ALLOCATABLE :: var_tmp(:,:)
341 
342  ALLOCATE(var_tmp(cs_res,cs_res))
343 
344  WRITE(res_ch,'(I4)') cs_res
345  DO tile_num = tile_beg, tile_end
346  WRITE(ich, '(I1)') tile_num
347  filename = "oro.C" // trim(adjustl(res_ch)) // ".tile" // ich // ".nc"
348  print *,'write inland to ',trim(filename)
349  stat = nf90_open(filename, nf90_write, ncid)
350  CALL nc_opchk(stat, "nf90_open oro_data.nc")
351  stat = nf90_inq_dimid(ncid, "lon", x_dimid)
352  CALL nc_opchk(stat, "nf90_inq_dim: x")
353  stat = nf90_inq_dimid(ncid, "lat", y_dimid)
354  CALL nc_opchk(stat, "nf90_inq_dim: y")
355 
356 ! original orodata netcdf file uses (y, x) order, so we made change to match it.
357  dimids = (/ x_dimid, y_dimid /)
358 
359 ! define a new variables
360  stat = nf90_inq_varid(ncid,"inland",inland_id) !safeguard if "inland" exists
361  IF (stat /= nf90_noerr) THEN
362  stat = nf90_redef(ncid)
363  CALL nc_opchk(stat, "nf90_redef")
364  stat = nf90_def_var(ncid,"inland",nf90_float,dimids,inland_id)
365  CALL nc_opchk(stat, "nf90_def_var: inland")
366  stat = nf90_put_att(ncid, inland_id,'coordinates','geolon geolat')
367  CALL nc_opchk(stat, "nf90_put_att: inland:coordinates")
368  stat = nf90_put_att(ncid, inland_id,'description', &
369  'inland = 1 indicates grid cells away from coast')
370  CALL nc_opchk(stat, "nf90_put_att: inland:description")
371  stat = nf90_enddef(ncid)
372  CALL nc_opchk(stat, "nf90_enddef")
373  ENDIF
374 
375  var_tmp(:,:) = inland(:,:,tile_num)
376  stat = nf90_put_var(ncid, inland_id, var_tmp, &
377  start = (/ 1, 1 /), count = (/ cs_res, cs_res /) )
378  CALL nc_opchk(stat, "nf90_put_var: inland")
379 
380  stat = nf90_close(ncid)
381  CALL nc_opchk(stat, "nf90_close oro_data.nc")
382  ENDDO
383  DEALLOCATE(var_tmp)
384 
385 END SUBROUTINE write_inland
386 
392 SUBROUTINE write_inland_reg(cs_res)
393  USE netcdf
394  INTEGER, INTENT(IN) :: cs_res
395 
396  CHARACTER(len=256) :: filename
397  CHARACTER(len=1) :: ich
398  CHARACTER(len=4) res_ch
399 
400  INTEGER :: tile_num
401  INTEGER :: stat, ncid, x_dimid, y_dimid, inland_id, dimids(2)
402  REAL, ALLOCATABLE :: var_tmp(:,:)
403  CHARACTER(len=8) dimname
404 
405  ALLOCATE(var_tmp(x_res,y_res))
406 
407  WRITE(res_ch,'(I4)') cs_res
408  tile_num = 7
409  WRITE(ich, '(I1)') tile_num
410  filename = "oro.C" // trim(adjustl(res_ch)) // ".tile" // ich // ".nc"
411  print*,'write inland to ',trim(filename)
412  stat = nf90_open(filename, nf90_write, ncid)
413  CALL nc_opchk(stat, "nf90_open oro_data.nc")
414  stat = nf90_inq_dimid(ncid, "lon", x_dimid)
415  CALL nc_opchk(stat, "nf90_inq_dim: x")
416  stat = nf90_inq_dimid(ncid, "lat", y_dimid)
417  CALL nc_opchk(stat, "nf90_inq_dim: y")
418  stat = nf90_inquire_dimension(ncid,x_dimid,dimname,len=x_res)
419  CALL nc_opchk(stat,'nf90_inquire_dimension: lon')
420  stat = nf90_inquire_dimension(ncid,y_dimid,dimname,len=y_res)
421  CALL nc_opchk(stat,'nf90_inquire_dimension: lon')
422 
423 ! original orodata netcdf file uses (y, x) order, so we made change to match it.
424  dimids = (/ x_dimid, y_dimid /)
425 
426 ! define a new variables
427  stat = nf90_inq_varid(ncid,"inland",inland_id) !safeguard if "inland" exists
428  IF (stat /= nf90_noerr) THEN
429  stat = nf90_redef(ncid)
430  CALL nc_opchk(stat, "nf90_redef")
431  stat = nf90_def_var(ncid,"inland",nf90_float,dimids,inland_id)
432  CALL nc_opchk(stat, "nf90_def_var: inland")
433  stat = nf90_put_att(ncid, inland_id,'coordinates','geolon geolat')
434  CALL nc_opchk(stat, "nf90_put_att: inland:coordinates")
435  stat = nf90_put_att(ncid, inland_id,'description', &
436  'inland = 1 indicates grid cells away from coast')
437  CALL nc_opchk(stat, "nf90_put_att: inland:description")
438  stat = nf90_enddef(ncid)
439  CALL nc_opchk(stat, "nf90_enddef")
440  ENDIF
441 
442  var_tmp(:,:) = inland(:,:,1)
443  stat = nf90_put_var(ncid, inland_id, var_tmp, &
444  start = (/ 1, 1 /), count = (/ x_res, y_res /) )
445  CALL nc_opchk(stat, "nf90_put_var: inland")
446 
447  stat = nf90_close(ncid)
448  CALL nc_opchk(stat, "nf90_close oro_data.nc")
449 
450  DEALLOCATE(var_tmp)
451 
452 END SUBROUTINE write_inland_reg
453 
455 SUBROUTINE free_mem()
457  DEALLOCATE(inland, land_frac)
458 
459 END SUBROUTINE free_mem
460 
467 SUBROUTINE nc_opchk(stat,opname)
468  USE netcdf
469  IMPLICIT NONE
470  INTEGER stat
471  CHARACTER(len=*) opname
472  CHARACTER(64) msg
473 
474  IF (stat .NE.0) THEN
475  msg = trim(opname) // ' Error, status code and message:'
476  print*,trim(msg), stat, nf90_strerror(stat)
477  stop
478  END IF
479 
480 END SUBROUTINE nc_opchk
481 
482 END PROGRAM inland_mask
483 
recursive subroutine mark_regional_inland_rec_d(i, j, t, rd)
Recursively walk through neighbors marking inland points for regional grid.
Definition: inland.F90:199
Neighboring cell descriptor.
Definition: nb.F90:17
subroutine mark_inland_reg(cs_res)
Create inland mask for regional grid.
Definition: inland.F90:105
subroutine read_orog(cs_res)
Read in orography (land fraction) data.
Definition: inland.F90:233
subroutine free_mem()
Deallocate module arrays.
Definition: inland.F90:456
recursive subroutine mark_global_inland_rec_d(i, j, t, rd)
Recursively walk through neighbors marking inland points for global grid.
Definition: inland.F90:162
subroutine write_inland(cs_res)
Write inland back to the orography data files for global grid.
Definition: inland.F90:331
subroutine nc_opchk(stat, opname)
Check NetCDF return code and print error message.
Definition: inland.F90:468
program inland_mask
This program creates the inland mask and writes it to the orography data files.
Definition: inland.F90:9
subroutine write_inland_reg(cs_res)
Write inland back to the orography data files for regional grid.
Definition: inland.F90:393
subroutine read_orog_reg(cs_res)
Read in orography (land fraction) data for regional grid.
Definition: inland.F90:279
subroutine mark_global_inland(cs_res)
Create inland mask for global grid.
Definition: inland.F90:80