orog_mask_tools  1.13.0
module_gsl_oro_data_lg_scale.f90
Go to the documentation of this file.
1 
22 module gsl_oro_data_lg_scale
23 
24 implicit none
25 
26 integer, parameter :: real_kind = selected_real_kind(6)
27 integer, parameter :: dbl_kind = selected_real_kind(13)
28 
29 real, parameter :: pi = 3.1415926535897_real_kind
30 integer :: dimx_fine
31 integer :: dimy_fine
32 
33 real (kind = real_kind), allocatable :: lat1d_fine(:)
34 real (kind = real_kind), allocatable :: lon1d_fine(:)
35 
36 real (kind = real_kind), parameter :: p5 = 0.5_real_kind
37 
38 real (kind = real_kind), allocatable :: hgt_m_fine(:,:)
39 real (kind = real_kind), parameter :: hgt_missing = 1.e+10
40 
41 contains
42 
50 subroutine calc_gsl_oro_data_lg_scale(tile_num,res_indx,halo)
51 
52 use netcdf
53 
54 implicit none
55 
56 character(len=2), intent(in) :: tile_num ! tile number
57 character(len=7), intent(in) :: res_indx ! grid-resolution index, e.g., 96, 192, 384, etc
58 character(len=4), intent(in) :: halo ! halo value (for input grid data)
59 
60 integer :: i,j,ii,jj
61 
62 integer :: ncid_in,ncid_out,err
63 integer :: varid
64 integer :: dimid,latid,lonid
65 integer, dimension (2) :: dimids
66 
67 integer :: nfinepoints ! number of fine grid points in each coarse grid cell
68 
69 real (kind = real_kind) :: sum2, sum4, var
70 
71 
72 real (kind = real_kind), allocatable :: &
73  zs(:,:)
74 
75 logical :: zs_accum
76 
77 real (kind = real_kind) :: zs_mean
78 real (kind = real_kind), allocatable :: &
79  std_dev(:),convexity(:), &
80  OA1(:),OA2(:),OA3(:),OA4(:), &
81  OL1(:),OL2(:),OL3(:),OL4(:)
82 
83 real (kind = real_kind), parameter :: max_convexity = 10._real_kind ! max value for convexity
84 
85 integer :: nu, nd, nw, nt
86 real (kind = real_kind) :: ratio
87 
88 
89 real, parameter :: ae = 6371200._real_kind ! Earth radius in meters
90 
91 character(len=35) :: FV3_grid_input_file_name
92 character(len=150) :: fine_topo_source_file_name
93 character(len=35) :: oro_data_output_file_name
94 
95 integer :: temp_int, dimX_FV3, dimY_FV3
96 real (kind = dbl_kind), allocatable :: lat_FV3_raw(:,:), lon_FV3_raw(:,:)
97 real (kind = real_kind), allocatable :: lat_FV3(:,:), lon_FV3(:,:)
98 real (kind = real_kind), allocatable :: lat_FV3_deg(:,:) ! saved version of latitude for output
99 real (kind = real_kind), allocatable :: lon_FV3_deg(:,:) ! saved version of longitude for output
100 real (kind = dbl_kind), allocatable :: area_FV3_qtr(:,:) ! meters squared
101 real (kind = real_kind), allocatable :: area_FV3(:,:) ! meters squared
102 real (kind = real_kind) :: dlta_lat, dlta_lon
103 
104 integer :: i_blk, j_blk
105 integer :: ii_loc, jj_loc, ii_m, jj_m
106 integer, dimension(3) :: s_ii, e_ii, s_jj, e_jj
107 real (kind = real_kind), dimension(3) :: lat_blk, lon_blk
108 real (kind = real_kind), dimension(3,3) :: HGT_M_coarse
109 real (kind = real_kind), allocatable :: HGT_M_coarse_on_fine(:,:)
110 integer :: cell_count ! allows for use of 1D arrays for GWD statistics fields
111 integer :: halo_int ! integer form of halo
112 
113 logical :: fexist
114 
115 logical, parameter :: detrend_topography = .true. ! switch for using detrended
116  ! or actual fine-grid topography
117  ! to represent subgrid terrain
118 
119 
120 print *, "Creating oro_data_ls file"
121 print *
122 
123 ! File name for file that contains grid information
124 if ( halo.eq."-999" ) then ! global or nested tile
125  fv3_grid_input_file_name = "C" // trim(res_indx) // "_grid.tile" // &
126  trim(tile_num) // ".nc"
127 else ! stand-alone regional tile
128  fv3_grid_input_file_name = "C" // trim(res_indx) // "_grid.tile" // &
129  trim(tile_num) // ".halo" // trim(halo) // ".nc"
130 end if
131 
132 print *, "Reading from file: ", fv3_grid_input_file_name
133 
134 ! Check that input file exists -- exit with error message if not
135 inquire(file=fv3_grid_input_file_name,exist=fexist)
136 if (.not.fexist) then
137  print *
138  print *, "Fatal error: Input file "//trim(fv3_grid_input_file_name)// &
139  " does not exist"
140  print *, "Exiting program gsl_oro_data.f90"
141  print *
142  call exit(4)
143 end if
144 
145 
146 ! In preparation for reading in grid data, account for existence
147 ! of halo points
148 if ( halo.eq."-999" ) then ! global or nested tile
149  halo_int = 0
150 else
151  read(halo,*) halo_int ! integer form of halo
152 end if
153 
154 
155 ! Open Cxxx_grid netCDF file for input and get dimensions
156 err = nf90_open(fv3_grid_input_file_name,nf90_nowrite,ncid_in)
157 call netcdf_err(err, 'opening: '//fv3_grid_input_file_name)
158 
159 err = nf90_inq_dimid(ncid_in,'nx',dimid)
160 call netcdf_err(err, 'reading nx id')
161 err = nf90_inquire_dimension(ncid_in,dimid,len=temp_int)
162 call netcdf_err(err, 'reading nx value')
163 dimx_fv3 = temp_int/2 - 2*halo_int ! shaving off any halo points from edges
164 
165 err = nf90_inq_dimid(ncid_in,'ny',dimid)
166 call netcdf_err(err, 'reading ny id')
167 err = nf90_inquire_dimension(ncid_in,dimid,len=temp_int)
168 call netcdf_err(err, 'reading ny value')
169 dimy_fv3 = temp_int/2 - 2*halo_int ! shaving off any halo points from edges
170 
171 print *, "dimX_FV3 =", dimx_fv3 ! number of model cells in x-direction
172 print *, "dimY_FV3 =", dimy_fv3 ! number of model cells in y-direction
173 print *
174 
175 ! Read in lat/lon (in degrees)
176 allocate (lat_fv3_raw((2*dimx_fv3+1),(2*dimy_fv3+1)))
177 err = nf90_inq_varid(ncid_in,'y',varid)
178 call netcdf_err(err, 'reading y id')
179 err = nf90_get_var(ncid_in,varid,lat_fv3_raw, &
180  start=(/1+2*halo_int,1+2*halo_int/), &
181  count=(/2*dimx_fv3+1,2*dimy_fv3+1/))
182 call netcdf_err(err, 'reading y')
183 
184 allocate (lon_fv3_raw((2*dimx_fv3+1),(2*dimy_fv3+1)))
185 err = nf90_inq_varid(ncid_in,'x',varid)
186 call netcdf_err(err, 'reading x id')
187 err = nf90_get_var(ncid_in,varid,lon_fv3_raw, &
188  start=(/1+2*halo_int,1+2*halo_int/), &
189  count=(/2*dimx_fv3+1,2*dimy_fv3+1/))
190 call netcdf_err(err, 'reading x')
191 
192 ! Read in quarter grid-cell areas
193 allocate (area_fv3_qtr((2*dimx_fv3),(2*dimy_fv3)))
194 err = nf90_inq_varid(ncid_in,'area',varid)
195 call netcdf_err(err, 'reading area id')
196 err = nf90_get_var(ncid_in,varid,area_fv3_qtr, &
197  start=(/1+2*halo_int,1+2*halo_int/), &
198  count=(/2*dimx_fv3,2*dimy_fv3/))
199 call netcdf_err(err, 'reading area')
200 
201 ! Calculate lat/lon at mass points (cell-centers)
202 ! Stride by 2 starting with 2nd point
203 ! NOTE: "Converting" from dbl_kind to real_kind
204 allocate (lat_fv3(dimx_fv3,dimy_fv3))
205 allocate (lon_fv3(dimx_fv3,dimy_fv3))
206 allocate (lat_fv3_deg(dimx_fv3,dimy_fv3))
207 allocate (lon_fv3_deg(dimx_fv3,dimy_fv3))
208 do j = 1,dimy_fv3
209  do i = 1,dimx_fv3
210  lat_fv3(i,j) = lat_fv3_raw(2*i,2*j)
211  lon_fv3(i,j) = lon_fv3_raw(2*i,2*j)
212  end do
213 end do
214 lat_fv3_deg(:,:) = lat_fv3(:,:)
215 lon_fv3_deg(:,:) = lon_fv3(:,:)
216 deallocate(lat_fv3_raw)
217 deallocate(lon_fv3_raw)
218 
219 ! Convert lat/lon to radians
220 lat_fv3 = lat_fv3*pi/180._real_kind
221 lon_fv3 = lon_fv3*pi/180._real_kind
222 
223 ! Create full grid-cell areas (4 raw areas per grid cell area)
224 ! NOTE: "Converting" from dbl_kind to real_kind
225 allocate(area_fv3(dimx_fv3,dimy_fv3))
226 do j = 1,dimy_fv3
227  do i = 1,dimx_fv3
228  area_fv3(i,j) = area_fv3_qtr(2*i-1,2*j-1) + area_fv3_qtr(2*i-1,2*j) + &
229  area_fv3_qtr(2*i,2*j-1) + area_fv3_qtr(2*i,2*j)
230  end do
231 end do
232 deallocate(area_fv3_qtr)
233 
234 err = nf90_close(ncid_in)
235 
236 
237 
238 ! Open file containing 2.5min topo data (fine grid)
239 fine_topo_source_file_name = "geo_em.d01.lat-lon.2.5m.HGT_M.nc"
240 ! Check that input file exists -- exit with error message if not
241 inquire(file=fine_topo_source_file_name,exist=fexist)
242 if (.not.fexist) then
243  print *
244  print *, "Fatal error: Topo source file "// &
245  trim(fine_topo_source_file_name)//" does not exist"
246  print *, "Exiting program gsl_oro_data.f90"
247  print *
248  call exit(4)
249 end if
250 err = nf90_open(trim(fine_topo_source_file_name),nf90_nowrite,ncid_in)
251 call netcdf_err(err, 'opening: '//trim(fine_topo_source_file_name))
252 
253 ! Get dimensions
254 err = nf90_inq_dimid(ncid_in,'west_east',dimid)
255 call netcdf_err(err, 'reading west_east id')
256 err = nf90_inquire_dimension(ncid_in,dimid,len=dimx_fine)
257 call netcdf_err(err, 'reading west_east value')
258 
259 err = nf90_inq_dimid(ncid_in,'south_north',dimid)
260 call netcdf_err(err, 'reading south_north id')
261 err = nf90_inquire_dimension(ncid_in,dimid,len=dimy_fine)
262 call netcdf_err(err, 'reading south_north value')
263 
264 print *, "Source file for high-resolution topography: ", &
265  trim(fine_topo_source_file_name)
266 print *, "dimX_fine =", dimx_fine
267 print *, "dimY_fine =", dimy_fine
268 print *
269 
270 
271 ! Read in lat/lon of fine grid
272 allocate(lat1d_fine(dimy_fine))
273 allocate(lon1d_fine(dimx_fine))
274 err = nf90_inq_varid(ncid_in,'CLAT',varid)
275 call netcdf_err(err, 'reading CLAT id')
276 err = nf90_get_var(ncid_in,varid,lat1d_fine,start=(/1,1/), &
277  count=(/1,dimy_fine/))
278 call netcdf_err(err, 'reading CLAT')
279 
280 err = nf90_inq_varid(ncid_in,'CLONG',varid)
281 call netcdf_err(err, 'reading CLONG id')
282 err = nf90_get_var(ncid_in,varid,lon1d_fine,start=(/1,1/), &
283  count=(/dimx_fine,1/))
284 call netcdf_err(err, 'reading CLONG')
285 
286 ! Convert lat/lon to radians
287 lat1d_fine = lat1d_fine*pi/180._real_kind
288 lon1d_fine = lon1d_fine*pi/180._real_kind
289 
290 
291 ! Reassign FV3 longitude to vary from -pi to pi to match lon1d_fine range
292 do j = 1,dimy_fv3
293  do i = 1,dimx_fv3
294  if ( lon_fv3(i,j).gt.pi ) then
295  lon_fv3(i,j) = lon_fv3(i,j) - 2*pi
296  end if
297  end do
298 end do
299 
300 
301 ! Read in fine-scale topography
302 allocate(hgt_m_fine(dimx_fine,dimy_fine))
303 err = nf90_inq_varid(ncid_in,'HGT_M',varid)
304 call netcdf_err(err, 'reading HGT_M id')
305 err = nf90_get_var(ncid_in,varid,hgt_m_fine,start=(/1,1/), &
306  count=(/dimx_fine,dimy_fine/))
307 call netcdf_err(err, 'reading HGT_M')
308 
309 
310 err = nf90_close(ncid_in)
311 
312 
313 ! Allocate GWD statistics fields
314 allocate (std_dev(dimx_fv3*dimy_fv3))
315 allocate (convexity(dimx_fv3*dimy_fv3))
316 allocate (oa1(dimx_fv3*dimy_fv3))
317 allocate (oa2(dimx_fv3*dimy_fv3))
318 allocate (oa3(dimx_fv3*dimy_fv3))
319 allocate (oa4(dimx_fv3*dimy_fv3))
320 allocate (ol1(dimx_fv3*dimy_fv3))
321 allocate (ol2(dimx_fv3*dimy_fv3))
322 allocate (ol3(dimx_fv3*dimy_fv3))
323 allocate (ol4(dimx_fv3*dimy_fv3))
324 
325 ! Initialize GWD statistics fields
326 std_dev(:) = 0._real_kind
327 convexity(:) = 0._real_kind
328 oa1(:) = 0._real_kind
329 oa2(:) = 0._real_kind
330 oa3(:) = 0._real_kind
331 oa4(:) = 0._real_kind
332 ol1(:) = 0._real_kind
333 ol2(:) = 0._real_kind
334 ol3(:) = 0._real_kind
335 ol4(:) = 0._real_kind
336 
337 
338 
339 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
340 ! This is a loop over all the FV3 (coarse) grid cells
341 ! The subgrid-scale topographic variables needed for the large-scale
342 ! orographic gravity wave drag schemes are calculated by the following steps:
343 ! 1) Sample the fine-scale (2.5min) topography contained within each
344 ! coarse grid cell.
345 ! 2) Detrend the topography by subtracting a bilinear-interpolated height field
346 ! from the fine-scale height field (if detrend_topography = .true.),
347 ! otherwise actual fine-scale height field is used to calculate statistics
348 ! 3) Calculate the orographic statistics: stddev,convexity,oa1,...oa4,
349 ! ol1,...,ol4
350 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
351 
352 cell_count = 1
353 
354 do j = 1,dimy_fv3
355  do i = 1,dimx_fv3
356 
357  ! Calculate approximate side-lengths of square lat-long "coarse" grid
358  ! cell centered on FV3 cell (units = radians)
359  dlta_lat = sqrt(area_fv3(i,j))/ae
360  dlta_lon = sqrt(area_fv3(i,j))/(ae*cos(lat_fv3(i,j)))
361 
362  ! Determine lat/lon of 9 lat-lon block centers
363  ! Note: lat_blk(2)/lon_blk(2) = lat_FV3(i,j)/lon_FV3(i,j)
364  ! Note: abs(lon_blk) may exceed pi
365  do i_blk = 1,3
366  lon_blk(i_blk) = lon_fv3(i,j) + (i_blk-2)*dlta_lon
367  end do
368  ! Note: abs(lat_blk) may exceed pi/2 (90 degrees)
369  do j_blk = 1,3
370  lat_blk(j_blk) = lat_fv3(i,j) + (j_blk-2)*dlta_lat
371  end do
372 
373  ! Find starting and ending fine-grid i,j indices for each
374  ! of the 9 "coarse-grid" blocks
375  ! Note: Index value of -999 is returned if latitude of grid points
376  ! exceed 90 degrees north or south
377  do i_blk = 1,3
378  s_ii(i_blk) = nearest_i_east(lon_blk(i_blk)-p5*dlta_lon)
379  e_ii(i_blk) = nearest_i_west(lon_blk(i_blk)+p5*dlta_lon)
380  end do
381  do j_blk = 1,3
382  s_jj(j_blk) = nearest_j_north(lat_blk(j_blk)-p5*dlta_lat)
383  e_jj(j_blk) = nearest_j_south(lat_blk(j_blk)+p5*dlta_lat)
384  end do
385 
386 
387  ! Calculate mean topographic height in each "coarse grid" block
388  ! Note: We only do the mean-height calculation if we are detrending
389  ! the subgrid topography, otherwise, we still need the
390  ! fine-grid indices for the block limits -- s_ii, etc.
391  do i_blk = 1,3
392 
393  ! "Shave" blocks on north or south due to proximity to poles
394  ! if necessary
395  j_blk = 1 ! southern row
396  ! Check for "shaved" block due to proximity to south pole
397  if ( (s_jj(j_blk).eq.-999).and.(e_jj(j_blk).ne.-999) ) then
398  s_jj(j_blk) = 1 ! southern boundary of shaved block
399  ! Reassign latitude of block center
400  lat_blk(j_blk) = p5*(lat1d_fine(1)+lat1d_fine(e_jj(j_blk)))
401  end if
402 
403  j_blk = 2 ! center row
404  ! Check for "shaved" block due to proximity to south or north pole
405  ! Note: We're assuming e_jj(2) and s_jj(2) can't both be -999
406  if ( s_jj(j_blk).eq.-999 ) then
407  s_jj(j_blk) = 1 ! block shaved on the south
408  ! Reassign latitude of block center
409  lat_blk(j_blk) = p5*(lat1d_fine(1)+lat1d_fine(e_jj(j_blk)))
410  end if
411  if ( e_jj(j_blk).eq.-999 ) then
412  e_jj(j_blk) = dimy_fine ! block shaved on the north
413  ! Reassign latitude of block center
414  lat_blk(j_blk) = p5*(lat1d_fine(s_jj(j_blk))+lat1d_fine(dimy_fine))
415  end if
416 
417  j_blk = 3 ! northern row
418  ! Check for "shaved" block due to proximity to north pole
419  if ( (e_jj(j_blk).eq.-999).and.(s_jj(j_blk).ne.-999) ) then
420  e_jj(j_blk) = dimy_fine ! northern boundary of shaved block
421  ! Reassign latitude of block center
422  lat_blk(j_blk) = p5*(lat1d_fine(s_jj(j_blk))+lat1d_fine(dimy_fine))
423  end if
424 
425  if ( detrend_topography ) then
426  do j_blk = 1,3
427  call calc_mean_hgt(s_ii(i_blk),e_ii(i_blk), &
428  s_jj(j_blk),e_jj(j_blk),hgt_m_coarse(i_blk,j_blk))
429  ! Note: If there is no block because s_jj and e_jj are
430  ! both -999 HGT_M_coarse returns with a "missing"
431  ! value of HGT_missing = 1.E+10
432  end do
433  end if
434 
435  end do
436 
437 
438  ! Calculate number of fine-grid points within center coarse block (2,2)
439  ! Check if center block straddles date line
440  if ( s_ii(2).gt.e_ii(2) ) then
441  ii_m = dimx_fine - s_ii(2) + 1 + e_ii(2)
442  else
443  ii_m = e_ii(2) - s_ii(2) + 1
444  end if
445  jj_m = e_jj(2) - s_jj(2) + 1
446 
447 
448  ! Bilinearly interpolate coarse-grid topography of the 9 blocks to
449  ! fine grid for the purpose of detrending the fine-grid topography
450  ! to represent the sub-grid topography
451  ! Note: The detrending only occurs within the center coarse block (2,2)
452  if ( detrend_topography ) then
453 
454  ! i,j indices of HGT_M_coarse_on_fine range from 1,ii_m and 1,jj_m
455  ! i.e., a "local" index system
456  allocate (hgt_m_coarse_on_fine(ii_m,jj_m))
457 
458  do jj = s_jj(2), e_jj(2)
459  jj_loc = jj - s_jj(2) + 1 ! local j-index (1 ... jj_m)
460  ! Check if block straddles the date line
461  if ( s_ii(2).gt.e_ii(2) ) then
462  do ii = s_ii(2), dimx_fine ! west of the date line
463  ii_loc = ii - s_ii(2) + 1 ! local i-index ( 1 ... ii_m)
464  call hgt_interpolate(lat1d_fine(jj),lon1d_fine(ii), &
465  lat_blk(:),lon_blk(:),hgt_m_coarse(:,:), &
466  hgt_m_coarse_on_fine(ii_loc,jj_loc))
467  end do
468  do ii = 1, e_ii(2) ! east of the date line
469  ii_loc = ii_loc + 1 ! local i-index ( 1 ... ii_m )
470  call hgt_interpolate(lat1d_fine(jj),lon1d_fine(ii), &
471  lat_blk(:),lon_blk(:),hgt_m_coarse(:,:), &
472  hgt_m_coarse_on_fine(ii_loc,jj_loc))
473  end do
474  else ! no crossing of the date line
475  do ii = s_ii(2), e_ii(2)
476  ii_loc = ii - s_ii(2) + 1 ! local i-index ( 1 ... ii_m)
477  call hgt_interpolate(lat1d_fine(jj),lon1d_fine(ii), &
478  lat_blk(:),lon_blk(:),hgt_m_coarse(:,:), &
479  hgt_m_coarse_on_fine(ii_loc,jj_loc))
480  end do
481  end if
482  end do
483 
484  end if
485 
486 
487  ! Assign values to "zs", which is the fine-grid surface topography field
488  ! that we will calculate statistics on, i.e, stddev, convexity, etc.
489  ! This will either be the detrended values (detrend_topography = .true.)
490  ! or the actual values (detrend_topography = .false.)
491  allocate (zs(ii_m,jj_m))
492 
493  do jj = s_jj(2), e_jj(2)
494  jj_loc = jj - s_jj(2) + 1 ! local j-index (1 ... jj_m)
495  ! Check if block straddles the date line
496  if ( s_ii(2).gt.e_ii(2) ) then
497  do ii = s_ii(2), dimx_fine ! west of the date line
498  ii_loc = ii - s_ii(2) + 1 ! local i-index ( 1 ... ii_m)
499  if ( detrend_topography ) then
500  zs(ii_loc,jj_loc) = hgt_m_fine(ii,jj) - &
501  hgt_m_coarse_on_fine(ii_loc,jj_loc)
502  else
503  zs(ii_loc,jj_loc) = hgt_m_fine(ii,jj)
504  end if
505  end do
506  do ii = 1, e_ii(2) ! east of the date line
507  ii_loc = ii_loc + 1 ! local i-index ( 1 ... ii_m )
508  if ( detrend_topography ) then
509  zs(ii_loc,jj_loc) = hgt_m_fine(ii,jj) - &
510  hgt_m_coarse_on_fine(ii_loc,jj_loc)
511  else
512  zs(ii_loc,jj_loc) = hgt_m_fine(ii,jj)
513  end if
514  end do
515  else ! no crossing of the date line
516  do ii = s_ii(2), e_ii(2)
517  ii_loc = ii - s_ii(2) + 1 ! local i-index ( 1 ... ii_m)
518  if ( detrend_topography ) then
519  zs(ii_loc,jj_loc) = hgt_m_fine(ii,jj) - &
520  hgt_m_coarse_on_fine(ii_loc,jj_loc)
521  else
522  zs(ii_loc,jj_loc) = hgt_m_fine(ii,jj)
523  end if
524  end do
525  end if
526  end do
527 
528 
529 
530  !
531  ! Finally, we can now calculate the topographic statistics fields needed
532  ! for the gravity wave drag scheme
533  !
534 
535  ! Make sure statistics are zero if there is no terrain in the grid cell
536  zs_accum = .false.
537  do jj = 1,jj_m
538  do ii = 1,ii_m
539  if ( abs(zs(ii,jj)).gt.1.e-3 ) zs_accum = .true.
540  end do
541  end do
542  if ( .not.zs_accum ) then ! no terrain in the grid cell
543  std_dev(cell_count) = 0._real_kind
544  convexity(cell_count) = 0._real_kind
545  oa1(cell_count) = 0._real_kind
546  oa2(cell_count) = 0._real_kind
547  oa3(cell_count) = 0._real_kind
548  oa4(cell_count) = 0._real_kind
549  ol1(cell_count) = 0._real_kind
550  ol2(cell_count) = 0._real_kind
551  ol3(cell_count) = 0._real_kind
552  ol4(cell_count) = 0._real_kind
553  if ( detrend_topography ) deallocate (hgt_m_coarse_on_fine)
554  deallocate(zs)
555  cell_count = cell_count + 1
556  cycle ! move on to next (coarse) grid cell
557  end if
558 
559 
560  !
561  ! Calculate standard deviation of subgrid-scale terrain height
562  !
563 
564  ! Calculate mean height
565  sum2 = 0._real_kind
566  nfinepoints = ii_m*jj_m
567  do jj = 1,jj_m
568  do ii = 1,ii_m
569  sum2 = sum2 + zs(ii,jj)
570  end do
571  end do
572  zs_mean = sum2 / real(nfinepoints,real_kind)
573 
574  ! Calculate standard deviation
575  sum2 = 0._real_kind
576  do jj = 1,jj_m
577  do ii = 1,ii_m
578  sum2 = sum2 + ( zs(ii,jj) - zs_mean )**2
579  end do
580  end do
581  std_dev(cell_count) = sqrt( sum2/real(nfinepoints,real_kind) )
582 
583 
584  !
585  ! Calculate convexity of sub-grid-scale terrain
586  !
587 
588  sum2 = 0._real_kind
589  sum4 = 0._real_kind
590  do jj = 1,jj_m
591  do ii = 1,ii_m
592  sum2 = sum2 + ( zs(ii,jj) - zs_mean )**2
593  sum4 = sum4 + ( zs(ii,jj) - zs_mean )**4
594  end do
595  end do
596 
597  var = sum2 / real(nfinepoints,real_kind)
598  if ( abs(var) < 1.0e-05_real_kind ) then
599  convexity(cell_count) = 0._real_kind
600  else
601  convexity(cell_count) = min( sum4 / ( var**2 * &
602  real(nfinepoints,real_kind) ), max_convexity )
603  end if
604 
605 
606  !
607  ! Calculate orographic asymmetries
608  !
609 
610  ! OA1 -- orographic asymmetry in West direction
611  nu = 0
612  nd = 0
613  do jj = 1,jj_m
614  if(mod(ii_m,2).eq.0.) then
615  do ii = 1,ii_m/2 ! left half of box
616  if ( zs(ii,jj) > zs_mean ) nu = nu + 1
617  end do
618  else
619  do ii = 1,ii_m/2+1 ! left half of box
620  if ( zs(ii,jj) > zs_mean ) nu = nu + 1
621  end do
622  endif
623  do ii = ii_m/2 + 1, ii_m ! right half of box
624  if ( zs(ii,jj) > zs_mean ) nd = nd + 1
625  end do
626  end do
627  if ( nu + nd > 0 ) then
628  oa1(cell_count) = real((nu - nd),real_kind) / &
629  real((nu + nd),real_kind)
630  else
631  oa1(cell_count) = 0._real_kind
632  end if
633 
634  ! OA2 -- orographic asymmetry in South direction
635  nu = 0
636  nd = 0
637  if(mod(jj_m,2).eq.0.) then
638  do jj = 1,jj_m/2 ! bottom half of box
639  do ii = 1,ii_m
640  if ( zs(ii,jj) > zs_mean ) nu = nu + 1
641  end do
642  end do
643  else
644  do jj = 1,jj_m/2+1 ! bottom half of box
645  do ii = 1,ii_m
646  if ( zs(ii,jj) > zs_mean ) nu = nu + 1
647  end do
648  end do
649  endif
650  do jj = jj_m/2 + 1,jj_m ! top half of box
651  do ii = 1, ii_m
652  if ( zs(ii,jj) > zs_mean ) nd = nd + 1
653  end do
654  end do
655  if ( nu + nd > 0 ) then
656  oa2(cell_count) = real((nu - nd),real_kind) / &
657  real((nu + nd),real_kind)
658  else
659  oa2(cell_count) = 0._real_kind
660  end if
661 
662  ! OA3 -- orographic asymmetry in South-West direction
663  nu = 0
664  nd = 0
665  ratio = real(jj_m,real_kind)/real(ii_m,real_kind)
666  do jj = 1,jj_m
667  do ii = 1,ii_m
668  if ( nint(real(ii,real_kind)*ratio) <= (jj_m - jj + 1) ) then
669  ! south-west half of box
670  if ( zs(ii,jj) > zs_mean ) nu = nu + 1
671  endif
672  if ( nint(real(ii,real_kind)*ratio) >= (jj_m - jj + 1) ) then
673  ! north-east half of box
674  if ( zs(ii,jj) > zs_mean ) nd = nd + 1
675  end if
676  end do
677  end do
678  if ( nu + nd > 0 ) then
679  oa3(cell_count) = real((nu - nd),real_kind) / &
680  real((nu + nd),real_kind)
681  else
682  oa3(cell_count) = 0._real_kind
683  end if
684 
685  ! OA4 -- orographic asymmetry in North-West direction
686  nu = 0
687  nd = 0
688  ratio = real(jj_m,real_kind)/real(ii_m,real_kind)
689  do jj = 1,jj_m
690  do ii = 1,ii_m
691  if ( nint(real(ii,real_kind)*ratio) <= jj ) then
692  ! north-west half of box
693  if ( zs(ii,jj) > zs_mean ) nu = nu + 1
694  end if
695  if ( nint(real(ii,real_kind)*ratio) >= jj ) then
696  ! south-east half of box
697  if ( zs(ii,jj) > zs_mean ) nd = nd + 1
698  end if
699  end do
700  end do
701  if ( nu + nd > 0 ) then
702  oa4(cell_count) = real((nu - nd),real_kind) / &
703  real((nu + nd),real_kind)
704  else
705  oa4(cell_count) = 0._real_kind
706  end if
707 
708 
709  !
710  ! Calculate orographic effective lengths
711  !
712 
713  ! OL1 -- orographic effective length for Westerly flow
714  nw = 0
715  nt = 0
716  do jj = max(jj_m/4,1), 3*jj_m/4
717  ! within central east-west band of box
718  do ii = 1, ii_m
719  if ( zs(ii,jj) > zs_mean ) nw = nw + 1
720  nt = nt + 1
721  end do
722  end do
723  if ( nt /= 0 ) then
724  ol1(cell_count) = real(nw,real_kind) / real(nt,real_kind)
725  else
726  ol1(cell_count) = 0._real_kind
727  end if
728 
729  ! OL2 -- orographic effective length for Southerly flow
730  nw = 0
731  nt = 0
732  do jj = 1, jj_m
733  do ii = max(ii_m/4,1), 3*ii_m/4
734  ! within central north-south band of box
735  if ( zs(ii,jj) > zs_mean ) nw = nw + 1
736  nt = nt + 1
737  end do
738  end do
739  if ( nt /= 0 ) then
740  ol2(cell_count) = real(nw,real_kind) / real(nt,real_kind)
741  else
742  ol2(cell_count) = 0._real_kind
743  end if
744 
745  ! OL3 -- orographic effective length for South-Westerly flow
746  nw = 0
747  nt = 0
748  do jj = 1, jj_m/2
749  do ii = 1, ii_m/2
750  if ( zs(ii,jj) > zs_mean ) nw = nw + 1
751  nt = nt + 1
752  end do
753  end do
754  do jj = jj_m/2+1, jj_m
755  do ii = ii_m/2+1, ii_m
756  if ( zs(ii,jj) > zs_mean ) nw = nw + 1
757  nt = nt + 1
758  end do
759  end do
760  if ( nt /= 0 ) then
761  ol3(cell_count) = real(nw,real_kind) / real(nt,real_kind)
762  else
763  ol3(cell_count) = 0._real_kind
764  end if
765 
766  ! OL4 -- orographic effective length for North-Westerly flow
767  nw = 0
768  nt = 0
769  do jj = jj_m/2+1, jj_m
770  do ii = 1, ii_m/2
771  if ( zs(ii,jj) > zs_mean ) nw = nw + 1
772  nt = nt + 1
773  end do
774  end do
775  do jj = 1, jj_m/2
776  do ii = ii_m/2+1, ii_m
777  if ( zs(ii,jj) > zs_mean ) nw = nw + 1
778  nt = nt + 1
779  end do
780  end do
781  if ( nt /= 0 ) then
782  ol4(cell_count) = real(nw,real_kind) / real(nt,real_kind)
783  else
784  ol4(cell_count) = 0._real_kind
785  end if
786 
787 
788 
789  if ( detrend_topography ) deallocate (hgt_m_coarse_on_fine)
790  deallocate (zs)
791 
792  cell_count = cell_count + 1
793 
794  end do ! j = 1,dimY_FV3
795 end do ! i = 1,dimX_FV3
796 
797 
798 
799 !
800 ! Output GWD statistics fields to netCDF file
801 !
802 
803 
804 if ( halo.eq."-999" ) then ! global or nested tile
805  oro_data_output_file_name = "C" // trim(res_indx) // "_oro_data_ls.tile" &
806  // trim(tile_num) // ".nc"
807 else ! stand-alone regional tile
808  oro_data_output_file_name = "C" // trim(res_indx) // "_oro_data_ls.tile" &
809  // trim(tile_num) // ".halo0.nc"
810 end if
811 
812 ! Open netCDF file for output
813 err = nf90_create(oro_data_output_file_name, nf90_clobber, ncid_out)
814 call netcdf_err(err, 'creating: '//oro_data_output_file_name)
815 
816 err = nf90_redef(ncid_out)
817 
818 ! Define dimensions
819 err = nf90_def_dim(ncid_out,'lon',dimx_fv3,lonid)
820 call netcdf_err(err, 'defining lon dimension')
821 err = nf90_def_dim(ncid_out,'lat',dimy_fv3,latid)
822 call netcdf_err(err, 'defining lat dimension')
823 
824 ! Define the 'dimensions vector' dimids to be used for writing
825 ! the 2-dimensional variables to the netCDF file
826 dimids(1) = lonid
827 dimids(2) = latid
828 
829 ! Define variables and attributes to put in the netCDF file
830 err = nf90_def_var(ncid_out,'geolon',nf90_float,dimids,varid)
831 call netcdf_err(err, 'defining geolon')
832 err = nf90_put_att(ncid_out,varid,'units','degrees')
833 err = nf90_put_att(ncid_out,varid,'description','longitude')
834 err = nf90_def_var(ncid_out,'geolat',nf90_float,dimids,varid)
835 call netcdf_err(err, 'defining geolat')
836 err = nf90_put_att(ncid_out,varid,'units','degrees')
837 err = nf90_put_att(ncid_out,varid,'description','latitude')
838 err = nf90_def_var(ncid_out,'stddev',nf90_float,dimids,varid)
839 call netcdf_err(err, 'stddev')
840 err = nf90_put_att(ncid_out,varid,'units','meters')
841 err = nf90_put_att(ncid_out,varid,'description', &
842  'standard deviation of subgrid topography')
843 err = nf90_def_var(ncid_out,'convexity',nf90_float,dimids,varid)
844 call netcdf_err(err, 'defining convexity')
845 err = nf90_put_att(ncid_out,varid,'units','-')
846 err = nf90_put_att(ncid_out,varid,'description', &
847  'convexity of subgrid topography')
848 err = nf90_def_var(ncid_out,'oa1',nf90_float,dimids,varid)
849 call netcdf_err(err, 'defining oa1')
850 err = nf90_put_att(ncid_out,varid,'units','-')
851 err = nf90_put_att(ncid_out,varid,'description', &
852  'orographic asymmetry in west direction')
853 err = nf90_def_var(ncid_out,'oa2',nf90_float,dimids,varid)
854 call netcdf_err(err, 'defining oa2')
855 err = nf90_put_att(ncid_out,varid,'units','-')
856 err = nf90_put_att(ncid_out,varid,'description', &
857  'orographic asymmetry in south direction')
858 err = nf90_def_var(ncid_out,'oa3',nf90_float,dimids,varid)
859 call netcdf_err(err, 'defining oa3')
860 err = nf90_put_att(ncid_out,varid,'units','-')
861 err = nf90_put_att(ncid_out,varid,'description', &
862  'orographic asymmetry in south-west direction')
863 err = nf90_def_var(ncid_out,'oa4',nf90_float,dimids,varid)
864 call netcdf_err(err, 'defining oa4')
865 err = nf90_put_att(ncid_out,varid,'units','-')
866 err = nf90_put_att(ncid_out,varid,'description', &
867  'orographic asymmetry in north-west direction')
868 err = nf90_def_var(ncid_out,'ol1',nf90_float,dimids,varid)
869 call netcdf_err(err, 'defining ol1')
870 err = nf90_put_att(ncid_out,varid,'units','-')
871 err = nf90_put_att(ncid_out,varid,'description', &
872  'orographic effective length for westerly flow')
873 err = nf90_def_var(ncid_out,'ol2',nf90_float,dimids,varid)
874 call netcdf_err(err, 'defining ol2')
875 err = nf90_put_att(ncid_out,varid,'units','-')
876 err = nf90_put_att(ncid_out,varid,'description', &
877  'orographic effective length for southerly flow')
878 err = nf90_def_var(ncid_out,'ol3',nf90_float,dimids,varid)
879 call netcdf_err(err, 'defining ol3')
880 err = nf90_put_att(ncid_out,varid,'units','-')
881 err = nf90_put_att(ncid_out,varid,'description', &
882  'orographic effective length for south-westerly flow')
883 err = nf90_def_var(ncid_out,'ol4',nf90_float,dimids,varid)
884 call netcdf_err(err, 'defining ol4')
885 err = nf90_put_att(ncid_out,varid,'units','-')
886 err = nf90_put_att(ncid_out,varid,'description', &
887  'orographic effective length for north-westerly flow')
888 
889 ! Add global attributes
890 err = nf90_put_att(ncid_out,nf90_global, &
891  'source_file_for_high-resolution_topography', &
892  trim(fine_topo_source_file_name))
893 if ( detrend_topography ) then
894  err = nf90_put_att(ncid_out,nf90_global, &
895  'high-res_topography_detrended','.TRUE.')
896 else
897  err = nf90_put_att(ncid_out,nf90_global, &
898  'high-res_topography_detrended','.FALSE.')
899 end if
900 
901 err = nf90_enddef(ncid_out)
902 
903 
904 ! Write data to output netCDF file
905 err = nf90_inq_varid(ncid_out,'geolon',varid)
906 call netcdf_err(err, 'reading geolon id')
907 err = nf90_put_var(ncid_out,varid,lon_fv3_deg,start=(/1,1/), &
908  count=(/dimx_fv3,dimy_fv3/))
909 call netcdf_err(err, 'writing geolon')
910 err = nf90_inq_varid(ncid_out,'geolat',varid)
911 call netcdf_err(err, 'reading geolat id')
912 err = nf90_put_var(ncid_out,varid,lat_fv3_deg,start=(/1,1/), &
913  count=(/dimx_fv3,dimy_fv3/))
914 call netcdf_err(err, 'writing geolat')
915 err = nf90_inq_varid(ncid_out,'stddev',varid)
916 call netcdf_err(err, 'reading stddev id')
917 err = nf90_put_var(ncid_out,varid,std_dev,start=(/1,1/), &
918  count=(/dimx_fv3,dimy_fv3/))
919 call netcdf_err(err, 'writing stddev')
920 err = nf90_inq_varid(ncid_out,'convexity',varid)
921 call netcdf_err(err, 'reading convexity id')
922 err = nf90_put_var(ncid_out,varid,convexity,start=(/1,1/), &
923  count=(/dimx_fv3,dimy_fv3/))
924 call netcdf_err(err, 'writing convexity')
925 err = nf90_inq_varid(ncid_out,'oa1',varid)
926 call netcdf_err(err, 'reading oa1 id')
927 err = nf90_put_var(ncid_out,varid,oa1,start=(/1,1/), &
928  count=(/dimx_fv3,dimy_fv3/))
929 call netcdf_err(err, 'writing oa1')
930 err = nf90_inq_varid(ncid_out,'oa2',varid)
931 call netcdf_err(err, 'reading oa2 id')
932 err = nf90_put_var(ncid_out,varid,oa2,start=(/1,1/), &
933  count=(/dimx_fv3,dimy_fv3/))
934 call netcdf_err(err, 'writing oa2')
935 err = nf90_inq_varid(ncid_out,'oa3',varid)
936 call netcdf_err(err, 'reading oa3 id')
937 err = nf90_put_var(ncid_out,varid,oa3,start=(/1,1/), &
938  count=(/dimx_fv3,dimy_fv3/))
939 call netcdf_err(err, 'writing oa3')
940 err = nf90_inq_varid(ncid_out,'oa4',varid)
941 call netcdf_err(err, 'reading oa4 id')
942 err = nf90_put_var(ncid_out,varid,oa4,start=(/1,1/), &
943  count=(/dimx_fv3,dimy_fv3/))
944 call netcdf_err(err, 'writing oa4')
945 err = nf90_inq_varid(ncid_out,'ol1',varid)
946 call netcdf_err(err, 'reading ol1 id')
947 err = nf90_put_var(ncid_out,varid,ol1,start=(/1,1/), &
948  count=(/dimx_fv3,dimy_fv3/))
949 call netcdf_err(err, 'writing ol1')
950 err = nf90_inq_varid(ncid_out,'ol2',varid)
951 call netcdf_err(err, 'reading ol2 id')
952 err = nf90_put_var(ncid_out,varid,ol2,start=(/1,1/), &
953  count=(/dimx_fv3,dimy_fv3/))
954 call netcdf_err(err, 'writing ol2')
955 err = nf90_inq_varid(ncid_out,'ol3',varid)
956 call netcdf_err(err, 'reading ol3 id')
957 err = nf90_put_var(ncid_out,varid,ol3,start=(/1,1/), &
958  count=(/dimx_fv3,dimy_fv3/))
959 call netcdf_err(err, 'writing ol3')
960 err = nf90_inq_varid(ncid_out,'ol4',varid)
961 call netcdf_err(err, 'reading ol4 id')
962 err = nf90_put_var(ncid_out,varid,ol4,start=(/1,1/), &
963  count=(/dimx_fv3,dimy_fv3/))
964 call netcdf_err(err, 'writing ol4')
965 
966 err = nf90_close(ncid_out)
967 
968 
969 
970 ! Deallocate arrays
971 deallocate(lat_fv3)
972 deallocate(lon_fv3)
973 deallocate(lat_fv3_deg)
974 deallocate(lon_fv3_deg)
975 deallocate(area_fv3)
976 deallocate(lat1d_fine)
977 deallocate(lon1d_fine)
978 deallocate(hgt_m_fine)
979 deallocate(std_dev)
980 deallocate(convexity)
981 deallocate(oa1)
982 deallocate(oa2)
983 deallocate(oa3)
984 deallocate(oa4)
985 deallocate(ol1)
986 deallocate(ol2)
987 deallocate(ol3)
988 deallocate(ol4)
989 
990 end subroutine calc_gsl_oro_data_lg_scale
991 
1000 subroutine calc_mean_hgt(s_ii,e_ii,s_jj,e_jj,HGT)
1002 ! This subroutine calculates the average terrain height within
1003 ! coarse grid cell ("block")
1004 
1005 implicit none
1006 
1007 integer :: s_ii, & ! starting fine-grid i-index
1008  e_ii, & ! ending fine-grid i-index
1009  s_jj, & ! starting fine-grid j-index
1010  e_jj ! ending fine-grid j-index
1011 real (kind=real_kind), intent(out) :: HGT
1012 
1013 ! Local variables
1014 integer :: i,j,grid_pt_count
1015 real (kind=real_kind) :: HGT_sum
1016 
1017 
1018 ! Return a value of 0 if s_jj and e_jj are both -999,
1019 ! i.e., if there is no block adjoining the center row
1020 ! due to proximity to one of the poles
1021 ! Note: The HGT value of the block will be ignored
1022 if ( (s_jj.eq.-999).and.(e_jj.eq.-999) ) then
1023  hgt = hgt_missing
1024  return
1025 end if
1026 
1027 grid_pt_count = 0
1028 hgt_sum = 0._real_kind
1029 do j = s_jj, e_jj
1030  ! Note: If the grid block straddles the date line, then s_ii > e_ii
1031  ! We need to correct for this
1032  if ( s_ii.gt.e_ii ) then ! straddling the date line
1033  do i = s_ii, dimx_fine ! west of the date line
1034  hgt_sum = hgt_sum + hgt_m_fine(i,j)
1035  grid_pt_count = grid_pt_count + 1
1036  end do
1037  do i = 1, e_ii ! east of the date line
1038  hgt_sum = hgt_sum + hgt_m_fine(i,j)
1039  grid_pt_count = grid_pt_count + 1
1040  end do
1041  else ! no crossing of the date line
1042  do i = s_ii, e_ii
1043  hgt_sum = hgt_sum + hgt_m_fine(i,j)
1044  grid_pt_count = grid_pt_count + 1
1045  end do
1046  end if
1047 end do
1048 hgt = hgt_sum/grid_pt_count
1049 
1050 end subroutine calc_mean_hgt
1051 
1061 subroutine hgt_interpolate(lat,lon_in,lat_blk,lon_blk,HGT_coarse, &
1062  HGT_coarse_on_fine)
1064 ! This subroutine bilinearly interpolates neighboring coarse-grid terrain
1065 ! heights (HGT_coarse) to fine-grid points (HGT_coarse_on_fine)
1066 ! (extrapolates in the case near poles)
1067 ! Note: Bilinear interpolation is done by calling a 1D interpolation
1068 ! function of a 1D interpolation function
1069 
1070 implicit none
1071 
1072 real (kind = real_kind), intent(in) :: &
1073  lat, & ! latitude of fine grid point
1074  lon_in ! longitude of fine grid point
1075 real (kind = real_kind), dimension(3),intent(in) :: &
1076  lat_blk, & ! latitudes of neighboring coarse grid points
1077  lon_blk ! longitudes of neighboring coarse grid points
1078 real (kind = real_kind), dimension(3,3), intent(in) :: HGT_coarse
1079 real (kind = real_kind), intent(out) :: HGT_coarse_on_fine
1080 real (kind = real_kind) :: lon
1081 
1082 
1083 lon = lon_in
1084 ! We need to make sure that if we're straddling the date line, that
1085 ! we remove the possible 2*pi discontinuity between lon and
1086 ! {lon_blk(1),lon_blk(2),lon_blk(3)) for interpolation purposes
1087 ! This will line the 4 longitudes up monotonically
1088 if ( abs(lon_in-lon_blk(2)).gt.pi ) then ! discontinuity exists
1089  if ( lon_in.gt.0. ) lon = lon - 2*pi ! lon_in lies west of date line
1090  if ( lon_in.lt.0. ) lon = lon + 2*pi ! lon_in lies east of date line
1091 end if
1092 
1093 
1094 ! Check for need to extrapolate if top or bottom block rows
1095 ! have height = HGT_missing
1096 
1097 ! Check for missing north row
1098 if ( (hgt_coarse(1,3).eq.hgt_missing).or.(hgt_coarse(2,3).eq.hgt_missing) &
1099  .or.(hgt_coarse(3,3).eq.hgt_missing) ) then
1100 
1101  ! Determine which quadrant of the coarse grid cell we are in
1102  if ( (lat.ge.lat_blk(2)).and.(lon.ge.lon_blk(2)) ) then ! Quadrant I
1103  ! Extrapolate from lat_blk(1) and lat_blk(2)
1104  hgt_coarse_on_fine = interp_1d( &
1105  lon,lon_blk(2),lon_blk(3), &
1106  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(2,1),hgt_coarse(2,2)), &
1107  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(3,1),hgt_coarse(3,2)) )
1108  elseif ( (lat.ge.lat_blk(2)).and.(lon.lt.lon_blk(2)) ) then ! Quadrant II
1109  ! Extrapolate from lat_blk(1) and lat_blk(2)
1110  hgt_coarse_on_fine = interp_1d( &
1111  lon,lon_blk(1),lon_blk(2), &
1112  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(1,1),hgt_coarse(1,2)), &
1113  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(2,1),hgt_coarse(2,2)) )
1114  elseif ( (lat.lt.lat_blk(2)).and.(lon.lt.lon_blk(2)) ) then ! Quadrant III
1115  hgt_coarse_on_fine = interp_1d( &
1116  lon,lon_blk(1),lon_blk(2), &
1117  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(1,1),hgt_coarse(1,2)), &
1118  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(2,1),hgt_coarse(2,2)) )
1119  elseif ( (lat.lt.lat_blk(2)).and.(lon.ge.lon_blk(2)) ) then ! Quadrant IV
1120  hgt_coarse_on_fine = interp_1d( &
1121  lon,lon_blk(2),lon_blk(3), &
1122  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(2,1),hgt_coarse(2,2)), &
1123  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(3,1),hgt_coarse(3,2)) )
1124  end if
1125 
1126  return
1127 end if
1128 
1129 ! Check for missing south row
1130 if ( (hgt_coarse(1,1).eq.hgt_missing).or.(hgt_coarse(2,1).eq.hgt_missing) &
1131  .or.(hgt_coarse(3,1).eq.hgt_missing) ) then
1132 
1133  ! Determine which quadrant of the coarse grid cell we are in
1134  if ( (lat.ge.lat_blk(2)).and.(lon.ge.lon_blk(2)) ) then ! Quadrant I
1135  hgt_coarse_on_fine = interp_1d( &
1136  lon,lon_blk(2),lon_blk(3), &
1137  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(2,2),hgt_coarse(2,3)), &
1138  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(3,2),hgt_coarse(3,3)) )
1139  elseif ( (lat.ge.lat_blk(2)).and.(lon.lt.lon_blk(2)) ) then ! Quadrant II
1140  hgt_coarse_on_fine = interp_1d( &
1141  lon,lon_blk(1),lon_blk(2), &
1142  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(1,2),hgt_coarse(1,3)), &
1143  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(2,2),hgt_coarse(2,3)) )
1144  elseif ( (lat.lt.lat_blk(2)).and.(lon.lt.lon_blk(2)) ) then ! Quadrant III
1145  ! Extrapolate from lat_blk(2) and lat_blk(3)
1146  hgt_coarse_on_fine = interp_1d( &
1147  lon,lon_blk(1),lon_blk(2), &
1148  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(1,2),hgt_coarse(1,3)), &
1149  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(2,2),hgt_coarse(2,3)) )
1150  elseif ( (lat.lt.lat_blk(2)).and.(lon.ge.lon_blk(2)) ) then ! Quadrant IV
1151  ! Extrapolate from lat_blk(2) and lat_blk(3)
1152  hgt_coarse_on_fine = interp_1d( &
1153  lon,lon_blk(2),lon_blk(3), &
1154  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(2,2),hgt_coarse(2,3)), &
1155  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(3,2),hgt_coarse(3,3)) )
1156  end if
1157 
1158  return
1159 end if
1160 
1161 ! Interpolation only
1162 ! Determine which quadrant of the coarse grid cell we are in
1163 if ( (lat.ge.lat_blk(2)).and.(lon.ge.lon_blk(2)) ) then ! Quadrant I
1164  hgt_coarse_on_fine = interp_1d( &
1165  lon,lon_blk(2),lon_blk(3), &
1166  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(2,2),hgt_coarse(2,3)), &
1167  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(3,2),hgt_coarse(3,3)) )
1168 elseif ( (lat.ge.lat_blk(2)).and.(lon.lt.lon_blk(2)) ) then ! Quadrant II
1169  hgt_coarse_on_fine = interp_1d( &
1170  lon,lon_blk(1),lon_blk(2), &
1171  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(1,2),hgt_coarse(1,3)), &
1172  interp_1d(lat,lat_blk(2),lat_blk(3),hgt_coarse(2,2),hgt_coarse(2,3)) )
1173 elseif ( (lat.lt.lat_blk(2)).and.(lon.lt.lon_blk(2)) ) then ! Quadrant III
1174  hgt_coarse_on_fine = interp_1d( &
1175  lon,lon_blk(1),lon_blk(2), &
1176  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(1,1),hgt_coarse(1,2)), &
1177  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(2,1),hgt_coarse(2,2)) )
1178 elseif ( (lat.lt.lat_blk(2)).and.(lon.ge.lon_blk(2)) ) then ! Quadrant IV
1179  hgt_coarse_on_fine = interp_1d( &
1180  lon,lon_blk(2),lon_blk(3), &
1181  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(2,1),hgt_coarse(2,2)), &
1182  interp_1d(lat,lat_blk(1),lat_blk(2),hgt_coarse(3,1),hgt_coarse(3,2)) )
1183 end if
1184 
1185 end subroutine hgt_interpolate
1186 
1192 function nearest_i_east(lon_in)
1193 ! Calculates nearest fine-grid i index to the east of (or on) a given longitude
1194 implicit none
1195 
1196 integer :: nearest_i_east
1197 real (kind=real_kind), intent(in) :: lon_in
1198 real (kind=real_kind) :: lon
1199 integer :: i
1200 
1201 lon = lon_in
1202 ! Make sure longitude is between -pi and pi
1203 do while ( (lon.lt.(-pi)).or.(lon.gt.pi) )
1204  if ( lon.lt.(-pi) ) lon = lon + 2*pi
1205  if ( lon.gt.pi ) lon = lon - 2*pi
1206 end do
1207 
1208 if ( lon.gt.lon1d_fine(dimx_fine) ) then
1209  nearest_i_east = 1
1210 else
1211  i = 1
1212  do while ( lon1d_fine(i).lt.lon )
1213  i = i + 1
1214  end do
1215  nearest_i_east = i
1216 end if
1217 
1218 end function nearest_i_east
1219 
1225 function nearest_i_west(lon_in)
1226 ! Calculates nearest fine-grid i index to the west of a given longitude
1227 implicit none
1228 
1229 integer :: nearest_i_west
1230 real (kind=real_kind), intent(in) :: lon_in
1231 real (kind=real_kind) :: lon
1232 integer :: i
1233 
1234 lon = lon_in
1235 ! Make sure longitude is between -pi and pi
1236 do while ( (lon.lt.(-pi)).or.(lon.gt.pi) )
1237  if ( lon.lt.(-pi) ) lon = lon + 2*pi
1238  if ( lon.gt.pi ) lon = lon - 2*pi
1239 end do
1240 
1241 if ( (lon.lt.lon1d_fine(1)).or.(lon.ge.lon1d_fine(dimx_fine)) ) then
1242  nearest_i_west = dimx_fine
1243 else
1244  i = 1
1245  do while ( lon1d_fine(i).le.lon )
1246  i = i + 1
1247  end do
1248  nearest_i_west = i - 1
1249 end if
1250 
1251 end function nearest_i_west
1252 
1258 function nearest_j_north(lat_in)
1259 ! Calculates nearest fine-grid j index to the north of a given latitude
1260 ! Note: If the abs(latitude) is greater than pi/2 (90 degrees) then
1261 ! the value -999 is returned
1262 implicit none
1263 
1264 integer :: nearest_j_north
1265 real (kind=real_kind), intent(in) :: lat_in
1266 real (kind=real_kind) :: lat
1267 integer :: j
1268 
1269 lat = lat_in
1270 if ( abs(lat_in).gt.p5*pi ) then
1271  nearest_j_north = -999
1272 else
1273  j = 1
1274  do while ( (lat1d_fine(j).lt.lat).and.(j.lt.dimy_fine) )
1275  j = j + 1
1276  end do
1277  nearest_j_north = j
1278 end if
1279 
1280 end function nearest_j_north
1281 
1287 function nearest_j_south(lat_in)
1288 ! Calculates nearest fine-grid j index to the south of a given latitude
1289 ! Note: If the abs(latitude) is greater than pi/2 (90 degrees) then
1290 ! the value -999 is returned
1291 implicit none
1292 
1293 integer :: nearest_j_south
1294 real (kind=real_kind), intent(in) :: lat_in
1295 real (kind=real_kind) :: lat
1296 integer :: j
1297 
1298 lat = lat_in
1299 if ( abs(lat_in).gt.p5*pi ) then
1300  nearest_j_south = -999
1301 elseif ( lat_in.le.lat1d_fine(1) ) then
1302  nearest_j_south = 1
1303 else
1304  j = 2
1305  do while ( (lat1d_fine(j).le.lat).and.(j.le.dimy_fine) )
1306  j = j + 1
1307  end do
1308  nearest_j_south = j - 1
1309 end if
1310 
1311 end function nearest_j_south
1312 
1322 function interp_1d(x,x1,x2,y1,y2)
1323 ! Interpolates (or extrapolates) linear function y = y(x)
1324 ! to x given y1 = y(x1) and y2 = y(x2)
1325 implicit none
1326 
1327 real (kind=real_kind) :: interp_1d
1328 real (kind=real_kind), intent(in) :: x,x1,x2,y1,y2
1329 real (kind=real_kind) :: slope
1330 
1331 ! Formula for a line: y = y1 + slope*(x - x1)
1332 slope = (y2-y1)/(x2-x1)
1333 interp_1d = y1 + slope*(x-x1)
1334 
1335 end function interp_1d
1336 
1342 subroutine netcdf_err(err,string)
1344 use netcdf
1345 
1346 implicit none
1347 
1348 integer, intent(in) :: err
1349 character(len=*), intent(in) :: string
1350 character(len=256) :: errmsg
1351 
1352 if (err.eq.nf90_noerr ) return
1353 errmsg = nf90_strerror(err)
1354 print *, ""
1355 print *, "FATAL ERROR: ", trim(string), ": ", trim(errmsg)
1356 print *, "STOP."
1357 call exit(4)
1358 
1359 return
1360 end subroutine netcdf_err
1361 
1362 end module gsl_oro_data_lg_scale
subroutine netcdf_err(err, string)
Check NetCDF error code and output the error message.
Definition: netcdf_io.F90:219