PageRenderTime 59ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/WPS/geogrid/src/proc_point_module.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 939 lines | 529 code | 143 blank | 267 comment | 97 complexity | 49fe9be22adce06243e5cdf1ba5ba4dd MD5 | raw file
Possible License(s): AGPL-1.0
  1. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. ! Module: proc_point_module
  3. !
  4. ! Purpose: This module provides routines that produce a value for a model grid
  5. ! point in two ways. If the field for which a value is being calculated is
  6. ! a continuous field, this module provided functionality to interpolate
  7. ! from the source array to the specified point. If the field is a categorical
  8. ! field, this module provided functionality to accumulate the values of all
  9. ! source points whose nearest model gridpoint is the specified point.
  10. ! Routines are also provided that help the caller determine an optimized
  11. ! order in which to process the model grid points.
  12. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  13. module proc_point_module
  14. ! Modules
  15. use bitarray_module
  16. use hash_module
  17. use misc_definitions_module
  18. use module_debug
  19. use source_data_module
  20. ! Information about which tile is in memory
  21. integer :: src_min_x, src_max_x, src_min_y, src_max_y, src_min_z, src_max_z, src_npts_bdr
  22. integer :: src_level
  23. character (len=128) :: src_fieldname
  24. character (len=256) :: src_fname
  25. ! Source tiles
  26. real, pointer, dimension(:,:,:) :: src_array
  27. ! Hash to track which tiles we have already processed
  28. type (hashtable) :: h_table
  29. contains
  30. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  31. ! Name: proc_point_init
  32. !
  33. ! Purpose: Initialize the module.
  34. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  35. subroutine proc_point_init()
  36. implicit none
  37. ! Initialize module variables
  38. src_min_x = INVALID
  39. src_min_y = INVALID
  40. src_min_z = INVALID
  41. src_max_x = INVALID
  42. src_max_y = INVALID
  43. src_max_z = INVALID
  44. src_fieldname = ' '
  45. src_fname = ' '
  46. nullify(src_array)
  47. call hash_init(h_table)
  48. end subroutine proc_point_init
  49. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  50. ! Name: proc_point_shutdown
  51. !
  52. ! Purpose: Do any cleanup work.
  53. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  54. subroutine proc_point_shutdown()
  55. implicit none
  56. ! Effectively reset the hash table that tracks which tiles have been processed
  57. ! by removing all entries
  58. call hash_destroy(h_table)
  59. if (associated(src_array)) deallocate(src_array)
  60. src_min_x = INVALID
  61. src_min_y = INVALID
  62. src_min_z = INVALID
  63. src_max_x = INVALID
  64. src_max_y = INVALID
  65. src_max_z = INVALID
  66. src_fieldname = ' '
  67. src_fname = ' '
  68. end subroutine proc_point_shutdown
  69. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  70. ! Name: accum_categorical
  71. !
  72. ! Purpose: Count the number of source points in each category whose nearest
  73. ! neighbor is the specified model grid point.
  74. !
  75. ! NOTE: When processing the source tile, those source points that are
  76. ! closest to a different model grid point will be added to the totals for
  77. ! such grid points; thus, an entire source tile will be processed at a time.
  78. ! This routine really processes for all model grid points that are
  79. ! within a source tile, and not just for a single grid point.
  80. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  81. subroutine accum_categorical(xlat, xlon, istagger, array, &
  82. start_i, end_i, start_j, end_j, &
  83. start_k, end_k, fieldname, processed_pts, &
  84. new_pts, ilevel, msgval, maskval, sr_x, sr_y)
  85. use llxy_module
  86. use bitarray_module
  87. implicit none
  88. ! Arguments
  89. integer, intent(in) :: start_i, end_i, start_j, end_j, start_k, end_k, &
  90. istagger, ilevel
  91. real, intent(in) :: xlat, xlon, msgval, maskval
  92. real, dimension(start_i:end_i, start_j:end_j, start_k:end_k), intent(inout) :: array
  93. character (len=128), intent(in) :: fieldname
  94. type (bitarray), intent(inout) :: processed_pts, new_pts
  95. integer, intent(in), optional :: sr_x, sr_y
  96. ! Local variables
  97. integer :: istatus, i, j
  98. integer :: current_domain, k
  99. integer, pointer, dimension(:,:,:) :: where_maps_to
  100. real :: rlat, rlon
  101. real :: rarea
  102. real :: rsr_x, rsr_y
  103. rlat = xlat
  104. if (xlon >= 180.) then
  105. rlon = xlon - 360.
  106. else
  107. rlon = xlon
  108. end if
  109. rsr_x = 1.0
  110. rsr_y = 1.0
  111. if (present(sr_x)) rsr_x = real(sr_x)
  112. if (present(sr_y)) rsr_y = real(sr_y)
  113. ! Assume source data is on unstaggered grid; specify M for istagger argument
  114. call get_data_tile(rlat, rlon, ilevel, fieldname, &
  115. src_fname, src_array, src_min_x, src_max_x, src_min_y, &
  116. src_max_y, src_min_z, src_max_z, src_npts_bdr, &
  117. istatus)
  118. src_fieldname = fieldname
  119. src_level = ilevel
  120. call hash_insert(h_table, src_fname)
  121. if (istatus /= 0) return
  122. allocate(where_maps_to(src_min_x:src_max_x,src_min_y:src_max_y,2))
  123. do i=src_min_x,src_max_x
  124. do j=src_min_y,src_max_y
  125. where_maps_to(i,j,1) = NOT_PROCESSED
  126. where_maps_to(i,j,2) = NOT_PROCESSED
  127. end do
  128. end do
  129. call process_categorical_block(src_array, istagger, where_maps_to, &
  130. src_min_x+src_npts_bdr, src_min_y+src_npts_bdr, src_min_z, &
  131. src_max_x-src_npts_bdr, src_max_y-src_npts_bdr, src_max_z, &
  132. array, start_i, end_i, start_j, end_j, start_k, end_k, &
  133. processed_pts, new_pts, ilevel, rsr_x, rsr_y, msgval, maskval)
  134. ! If a grid cell has less than half of its area covered by data from this source,
  135. ! then clear the cell and let another source fill in the cell
  136. if (ilevel > 1) then
  137. do i=start_i,end_i
  138. do j=start_j,end_j
  139. if (bitarray_test(new_pts, i-start_i+1, j-start_j+1) .and. &
  140. .not. bitarray_test(processed_pts, i-start_i+1, j-start_j+1)) then
  141. rarea = 0.
  142. do k=start_k,end_k
  143. rarea = rarea + array(i,j,k)
  144. end do
  145. current_domain = iget_selected_domain()
  146. call select_domain(SOURCE_PROJ)
  147. if (proj_stack(current_nest_number)%dx < 0.) then
  148. rarea = rarea * (proj_stack(current_nest_number)%latinc*111000.)**2.0
  149. else
  150. rarea = rarea * proj_stack(current_nest_number)%dx**2.0
  151. end if
  152. call select_domain(current_domain)
  153. if (proj_stack(current_nest_number)%dx < 0.) then
  154. if ((proj_stack(current_nest_number)%latinc*111000.)**2.0 > 2.0*rarea) then
  155. do k=start_k,end_k
  156. array(i,j,k) = 0.
  157. end do
  158. call bitarray_clear(new_pts, i-start_i+1, j-start_j+1)
  159. end if
  160. else
  161. if (proj_stack(current_nest_number)%dx**2.0 > 2.0*rarea) then
  162. do k=start_k,end_k
  163. array(i,j,k) = 0.
  164. end do
  165. call bitarray_clear(new_pts, i-start_i+1, j-start_j+1)
  166. end if
  167. end if
  168. end if
  169. end do
  170. end do
  171. end if
  172. deallocate(where_maps_to)
  173. end subroutine accum_categorical
  174. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  175. ! Name: process_categorical_block
  176. !
  177. ! Purpose: To recursively process a subarray of categorical data, assigning
  178. ! the points in a block to their nearest grid point. The nearest neighbor
  179. ! may be estimated in some cases; for example, if the four corners of a
  180. ! subarray all have the same nearest grid point, all elements in the
  181. ! subarray are assigned to that grid point.
  182. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  183. recursive subroutine process_categorical_block(tile_array, istagger, where_maps_to, &
  184. min_i, min_j, min_k, max_i, max_j, max_k, dst_array, &
  185. start_x, end_x, start_y, end_y, start_z, end_z, &
  186. processed_pts, new_pts, ilevel, sr_x, sr_y, &
  187. msgval, maskval, mask_array)
  188. use llxy_module
  189. implicit none
  190. ! Arguments
  191. integer, intent(in) :: min_i, min_j, min_k, max_i, max_j, max_k, istagger, &
  192. start_x, end_x, start_y, end_y, start_z, end_z, ilevel
  193. integer, dimension(src_min_x:src_max_x,src_min_y:src_max_y,2), intent(inout) :: where_maps_to
  194. real, intent(in) :: sr_x, sr_y, msgval, maskval
  195. real, dimension(src_min_x:src_max_x,src_min_y:src_max_y,src_min_z:src_max_z), intent(in) :: tile_array
  196. real, dimension(start_x:end_x,start_y:end_y,start_z:end_z), intent(inout) :: dst_array
  197. real, dimension(src_min_x:src_max_x,src_min_y:src_max_y), intent(in), optional :: mask_array
  198. type (bitarray), intent(inout) :: processed_pts, new_pts
  199. ! Local variables
  200. integer :: x_dest, y_dest, i, j, k, center_i, center_j, current_domain
  201. real :: lat_corner, lon_corner, rx, ry
  202. ! Compute the model grid point that the corners of the rectangle to be
  203. ! processed map to
  204. ! Lower-left corner
  205. if (where_maps_to(min_i,min_j,1) == NOT_PROCESSED) then
  206. current_domain = iget_selected_domain()
  207. call select_domain(SOURCE_PROJ)
  208. call xytoll(real(min_i), real(min_j), lat_corner, lon_corner, M)
  209. call select_domain(current_domain)
  210. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  211. rx = (rx-0.5) * sr_x + 0.5/sr_x
  212. ry = (ry-0.5) * sr_y + 0.5/sr_y
  213. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  214. where_maps_to(min_i,min_j,1) = nint(rx)
  215. where_maps_to(min_i,min_j,2) = nint(ry)
  216. else
  217. where_maps_to(min_i,min_j,1) = OUTSIDE_DOMAIN
  218. end if
  219. end if
  220. ! Upper-left corner
  221. if (where_maps_to(min_i,max_j,1) == NOT_PROCESSED) then
  222. current_domain = iget_selected_domain()
  223. call select_domain(SOURCE_PROJ)
  224. call xytoll(real(min_i), real(max_j), lat_corner, lon_corner, M)
  225. call select_domain(current_domain)
  226. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  227. rx = (rx-0.5) * sr_x + 0.5/sr_x
  228. ry = (ry-0.5) * sr_y + 0.5/sr_y
  229. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  230. where_maps_to(min_i,max_j,1) = nint(rx)
  231. where_maps_to(min_i,max_j,2) = nint(ry)
  232. else
  233. where_maps_to(min_i,max_j,1) = OUTSIDE_DOMAIN
  234. end if
  235. end if
  236. ! Upper-right corner
  237. if (where_maps_to(max_i,max_j,1) == NOT_PROCESSED) then
  238. current_domain = iget_selected_domain()
  239. call select_domain(SOURCE_PROJ)
  240. call xytoll(real(max_i), real(max_j), lat_corner, lon_corner, M)
  241. call select_domain(current_domain)
  242. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  243. rx = (rx-0.5) * sr_x + 0.5/sr_x
  244. ry = (ry-0.5) * sr_y + 0.5/sr_y
  245. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  246. where_maps_to(max_i,max_j,1) = nint(rx)
  247. where_maps_to(max_i,max_j,2) = nint(ry)
  248. else
  249. where_maps_to(max_i,max_j,1) = OUTSIDE_DOMAIN
  250. end if
  251. end if
  252. ! Lower-right corner
  253. if (where_maps_to(max_i,min_j,1) == NOT_PROCESSED) then
  254. current_domain = iget_selected_domain()
  255. call select_domain(SOURCE_PROJ)
  256. call xytoll(real(max_i), real(min_j), lat_corner, lon_corner, M)
  257. call select_domain(current_domain)
  258. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  259. rx = (rx-0.5) * sr_x + 0.5/sr_x
  260. ry = (ry-0.5) * sr_y + 0.5/sr_y
  261. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  262. where_maps_to(max_i,min_j,1) = nint(rx)
  263. where_maps_to(max_i,min_j,2) = nint(ry)
  264. else
  265. where_maps_to(max_i,min_j,1) = OUTSIDE_DOMAIN
  266. end if
  267. end if
  268. ! If all four corners map to same model grid point, accumulate the
  269. ! entire rectangle
  270. if (where_maps_to(min_i,min_j,1) == where_maps_to(min_i,max_j,1) .and. &
  271. where_maps_to(min_i,min_j,1) == where_maps_to(max_i,max_j,1) .and. &
  272. where_maps_to(min_i,min_j,1) == where_maps_to(max_i,min_j,1) .and. &
  273. where_maps_to(min_i,min_j,2) == where_maps_to(min_i,max_j,2) .and. &
  274. where_maps_to(min_i,min_j,2) == where_maps_to(max_i,max_j,2) .and. &
  275. where_maps_to(min_i,min_j,2) == where_maps_to(max_i,min_j,2) .and. &
  276. where_maps_to(min_i,min_j,1) /= OUTSIDE_DOMAIN) then
  277. x_dest = where_maps_to(min_i,min_j,1)
  278. y_dest = where_maps_to(min_i,min_j,2)
  279. ! If this grid point was already given a value from higher-priority source data,
  280. ! there is nothing to do.
  281. if (.not. bitarray_test(processed_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  282. ! If this grid point has never been given a value by this level of source data,
  283. ! initialize the point
  284. if (.not. bitarray_test(new_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  285. do k=start_z,end_z
  286. dst_array(x_dest,y_dest,k) = 0.
  287. end do
  288. end if
  289. ! Count all the points whose nearest neighbor is this grid point
  290. if (present(mask_array)) then
  291. do i=min_i,max_i
  292. do j=min_j,max_j
  293. ! Ignore masked/missing values in the source data
  294. if ((tile_array(i,j,min_k) /= msgval) .and. &
  295. (mask_array(i,j) /= maskval)) then
  296. if (int(tile_array(i,j,min_k)) >= start_z .and. int(tile_array(i,j,min_k)) <= end_z) then
  297. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) = &
  298. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) + 1.0
  299. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  300. else
  301. call mprintf(.true., WARN, 'In source tile %s, point (%i, %i) has '// &
  302. 'an invalid category of %i', &
  303. s1=trim(src_fname), i1=i, i2=j, i3=int(tile_array(i,j,min_k)))
  304. end if
  305. end if
  306. end do
  307. end do
  308. else
  309. do i=min_i,max_i
  310. do j=min_j,max_j
  311. ! Ignore masked/missing values in the source data
  312. if (tile_array(i,j,min_k) /= msgval) then
  313. if (int(tile_array(i,j,min_k)) >= start_z .and. int(tile_array(i,j,min_k)) <= end_z) then
  314. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) = &
  315. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) + 1.0
  316. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  317. else
  318. call mprintf(.true., WARN, 'In source tile %s, point (%i, %i) '// &
  319. 'has an invalid category of %i', &
  320. s1=trim(src_fname), i1=i, i2=j, i3=int(tile_array(i,j,min_k)))
  321. end if
  322. end if
  323. end do
  324. end do
  325. end if
  326. end if
  327. ! Rectangle is a square of four points, and we can simply deal with each of the points
  328. else if (((max_i - min_i + 1) <= 2) .and. ((max_j - min_j + 1) <= 2)) then
  329. do i=min_i,max_i
  330. do j=min_j,max_j
  331. x_dest = where_maps_to(i,j,1)
  332. y_dest = where_maps_to(i,j,2)
  333. if (x_dest /= OUTSIDE_DOMAIN) then
  334. if (.not. bitarray_test(processed_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  335. if (.not. bitarray_test(new_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  336. do k=start_z,end_z
  337. dst_array(x_dest,y_dest,k) = 0.
  338. end do
  339. end if
  340. ! Ignore masked/missing values
  341. if (present(mask_array)) then
  342. if ((tile_array(i,j,min_k) /= msgval) .and. &
  343. (mask_array(i,j) /= maskval)) then
  344. if (int(tile_array(i,j,min_k)) >= start_z .and. int(tile_array(i,j,min_k)) <= end_z) then
  345. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) = &
  346. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) + 1.0
  347. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  348. else
  349. call mprintf(.true., WARN, 'In source tile %s, point (%i, %i) has '// &
  350. 'an invalid category of %i', &
  351. s1=trim(src_fname), i1=i, i2=j, i3=int(tile_array(i,j,min_k)))
  352. end if
  353. end if
  354. else
  355. if (tile_array(i,j,min_k) /= msgval) then
  356. if (int(tile_array(i,j,min_k)) >= start_z .and. int(tile_array(i,j,min_k)) <= end_z) then
  357. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) = &
  358. dst_array(x_dest,y_dest,int(tile_array(i,j,min_k))) + 1.0
  359. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  360. else
  361. call mprintf(.true., WARN, 'In source tile %s, point (%i, %i) has '// &
  362. 'an invalid category of %i', &
  363. s1=trim(src_fname), i1=i, i2=j, i3=int(tile_array(i,j,min_k)))
  364. end if
  365. end if
  366. end if
  367. end if
  368. end if
  369. end do
  370. end do
  371. ! Not all corners map to the same grid point, and the rectangle contains more than
  372. ! four points
  373. else
  374. center_i = (max_i + min_i)/2
  375. center_j = (max_j + min_j)/2
  376. ! Recursively process lower-left rectangle
  377. call process_categorical_block(tile_array, istagger, where_maps_to, min_i, min_j, min_k, center_i, &
  378. center_j, max_k, dst_array, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  379. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  380. ! Recursively process lower-right rectangle
  381. if (center_i < max_i) then
  382. call process_categorical_block(tile_array, istagger, where_maps_to, center_i+1, min_j, min_k, max_i, &
  383. center_j, max_k, dst_array, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  384. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  385. end if
  386. ! Recursively process upper-left rectangle
  387. if (center_j < max_j) then
  388. call process_categorical_block(tile_array, istagger, where_maps_to, min_i, center_j+1, min_k, center_i, &
  389. max_j, max_k, dst_array, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  390. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  391. end if
  392. ! Recursively process upper-right rectangle
  393. if (center_i < max_i .and. center_j < max_j) then
  394. call process_categorical_block(tile_array, istagger, where_maps_to, center_i+1, center_j+1, min_k, max_i, &
  395. max_j, max_k, dst_array, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  396. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  397. end if
  398. end if
  399. end subroutine process_categorical_block
  400. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  401. ! Name: accum_continuous
  402. !
  403. ! Purpose: Sum up all of the source data points whose nearest neighbor in the
  404. ! model grid is the specified model grid point.
  405. !
  406. ! NOTE: When processing the source tile, those source points that are
  407. ! closest to a different model grid point will be added to the totals for
  408. ! such grid points; thus, an entire source tile will be processed at a time.
  409. ! This routine really processes for all model grid points that are
  410. ! within a source tile, and not just for a single grid point.
  411. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  412. subroutine accum_continuous(xlat, xlon, istagger, array, n, &
  413. start_i, end_i, start_j, end_j, &
  414. start_k, end_k, fieldname, processed_pts, &
  415. new_pts, ilevel, msgval, maskval, sr_x, sr_y)
  416. implicit none
  417. ! Arguments
  418. integer, intent(in) :: start_i, end_i, start_j, end_j, start_k, end_k, &
  419. istagger, ilevel
  420. real, intent(in) :: xlat, xlon, msgval, maskval
  421. real, dimension(start_i:end_i, start_j:end_j, start_k:end_k), intent(inout) :: array, n
  422. character (len=128), intent(in) :: fieldname
  423. type (bitarray), intent(inout) :: processed_pts, new_pts
  424. integer, intent(in), optional :: sr_x, sr_y
  425. ! Local variables
  426. integer :: istatus, i, j
  427. integer, pointer, dimension(:,:,:) :: where_maps_to
  428. real :: rlat, rlon
  429. real :: rsr_x, rsr_y
  430. rlat = xlat
  431. if (xlon >= 180.) then
  432. rlon = xlon - 360.
  433. else
  434. rlon = xlon
  435. end if
  436. rsr_x = 1.0
  437. rsr_y = 1.0
  438. if (present(sr_x)) rsr_x = real(sr_x)
  439. if (present(sr_y)) rsr_y = real(sr_y)
  440. ! Assume source data is on unstaggered grid; specify M for istagger argument
  441. call get_data_tile(rlat, rlon, ilevel, fieldname, &
  442. src_fname, src_array, src_min_x, src_max_x, src_min_y, &
  443. src_max_y, src_min_z, src_max_z, src_npts_bdr, &
  444. istatus)
  445. src_fieldname = fieldname
  446. src_level = ilevel
  447. call hash_insert(h_table, src_fname)
  448. if (istatus /= 0) then
  449. src_min_x = INVALID
  450. src_min_y = INVALID
  451. src_max_x = INVALID
  452. src_max_y = INVALID
  453. return
  454. end if
  455. allocate(where_maps_to(src_min_x:src_max_x,src_min_y:src_max_y,2))
  456. do i=src_min_x,src_max_x
  457. do j=src_min_y,src_max_y
  458. where_maps_to(i,j,1) = NOT_PROCESSED
  459. end do
  460. end do
  461. call process_continuous_block(src_array, istagger, where_maps_to, &
  462. src_min_x+src_npts_bdr, src_min_y+src_npts_bdr, src_min_z, &
  463. src_max_x-src_npts_bdr, src_max_y-src_npts_bdr, src_max_z, &
  464. array, n, start_i, end_i, start_j, end_j, start_k, end_k, &
  465. processed_pts, new_pts, ilevel, rsr_x, rsr_y, msgval, maskval)
  466. deallocate(where_maps_to)
  467. end subroutine accum_continuous
  468. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  469. ! Name: process_continuous_block
  470. !
  471. ! Purpose: To recursively process a subarray of continuous data, adding the
  472. ! points in a block to the sum for their nearest grid point. The nearest
  473. ! neighbor may be estimated in some cases; for example, if the four corners
  474. ! of a subarray all have the same nearest grid point, all elements in the
  475. ! subarray are added to that grid point.
  476. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  477. recursive subroutine process_continuous_block(tile_array, istagger, where_maps_to, &
  478. min_i, min_j, min_k, max_i, max_j, max_k, dst_array, n, &
  479. start_x, end_x, start_y, end_y, start_z, end_z, &
  480. processed_pts, new_pts, ilevel, sr_x, sr_y, &
  481. msgval, maskval, mask_array)
  482. use llxy_module
  483. implicit none
  484. ! Arguments
  485. integer, intent(in) :: min_i, min_j, min_k, max_i, max_j, max_k, istagger, &
  486. start_x, end_x, start_y, end_y, start_z, end_z, ilevel
  487. integer, dimension(src_min_x:src_max_x,src_min_y:src_max_y,2), intent(inout) :: where_maps_to
  488. real, intent(in) :: sr_x, sr_y, msgval, maskval
  489. real, dimension(src_min_x:src_max_x,src_min_y:src_max_y,src_min_z:src_max_z), intent(in) :: tile_array
  490. real, dimension(start_x:end_x,start_y:end_y,start_z:end_z), intent(inout) :: dst_array, n
  491. real, dimension(src_min_x:src_max_x,src_min_y:src_max_y), intent(in), optional :: mask_array
  492. type (bitarray), intent(inout) :: processed_pts, new_pts
  493. ! Local variables
  494. integer :: x_dest, y_dest, i, j, k, center_i, center_j, current_domain
  495. real :: lat_corner, lon_corner, rx, ry
  496. ! Compute the model grid point that the corners of the rectangle to be
  497. ! processed map to
  498. ! Lower-left corner
  499. if (where_maps_to(min_i,min_j,1) == NOT_PROCESSED) then
  500. current_domain = iget_selected_domain()
  501. call select_domain(SOURCE_PROJ)
  502. call xytoll(real(min_i), real(min_j), lat_corner, lon_corner, M)
  503. call select_domain(current_domain)
  504. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  505. rx = (rx-0.5) * sr_x + 0.5/sr_x
  506. ry = (ry-0.5) * sr_y + 0.5/sr_y
  507. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  508. where_maps_to(min_i,min_j,1) = nint(rx)
  509. where_maps_to(min_i,min_j,2) = nint(ry)
  510. else
  511. where_maps_to(min_i,min_j,1) = OUTSIDE_DOMAIN
  512. end if
  513. end if
  514. ! Upper-left corner
  515. if (where_maps_to(min_i,max_j,1) == NOT_PROCESSED) then
  516. current_domain = iget_selected_domain()
  517. call select_domain(SOURCE_PROJ)
  518. call xytoll(real(min_i), real(max_j), lat_corner, lon_corner, M)
  519. call select_domain(current_domain)
  520. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  521. rx = (rx-0.5) * sr_x + 0.5/sr_x
  522. ry = (ry-0.5) * sr_y + 0.5/sr_y
  523. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  524. where_maps_to(min_i,max_j,1) = nint(rx)
  525. where_maps_to(min_i,max_j,2) = nint(ry)
  526. else
  527. where_maps_to(min_i,max_j,1) = OUTSIDE_DOMAIN
  528. end if
  529. end if
  530. ! Upper-right corner
  531. if (where_maps_to(max_i,max_j,1) == NOT_PROCESSED) then
  532. current_domain = iget_selected_domain()
  533. call select_domain(SOURCE_PROJ)
  534. call xytoll(real(max_i), real(max_j), lat_corner, lon_corner, M)
  535. call select_domain(current_domain)
  536. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  537. rx = (rx-0.5) * sr_x + 0.5/sr_x
  538. ry = (ry-0.5) * sr_y + 0.5/sr_y
  539. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  540. where_maps_to(max_i,max_j,1) = nint(rx)
  541. where_maps_to(max_i,max_j,2) = nint(ry)
  542. else
  543. where_maps_to(max_i,max_j,1) = OUTSIDE_DOMAIN
  544. end if
  545. end if
  546. ! Lower-right corner
  547. if (where_maps_to(max_i,min_j,1) == NOT_PROCESSED) then
  548. current_domain = iget_selected_domain()
  549. call select_domain(SOURCE_PROJ)
  550. call xytoll(real(max_i), real(min_j), lat_corner, lon_corner, M)
  551. call select_domain(current_domain)
  552. call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
  553. rx = (rx-0.5) * sr_x + 0.5/sr_x
  554. ry = (ry-0.5) * sr_y + 0.5/sr_y
  555. if (real(start_x) <= rx .and. rx <= real(end_x) .and. real(start_y) <= ry .and. ry <= real(end_y)) then
  556. where_maps_to(max_i,min_j,1) = nint(rx)
  557. where_maps_to(max_i,min_j,2) = nint(ry)
  558. else
  559. where_maps_to(max_i,min_j,1) = OUTSIDE_DOMAIN
  560. end if
  561. end if
  562. ! If all four corners map to same model grid point, accumulate the
  563. ! entire rectangle
  564. if (where_maps_to(min_i,min_j,1) == where_maps_to(min_i,max_j,1) .and. &
  565. where_maps_to(min_i,min_j,1) == where_maps_to(max_i,max_j,1) .and. &
  566. where_maps_to(min_i,min_j,1) == where_maps_to(max_i,min_j,1) .and. &
  567. where_maps_to(min_i,min_j,2) == where_maps_to(min_i,max_j,2) .and. &
  568. where_maps_to(min_i,min_j,2) == where_maps_to(max_i,max_j,2) .and. &
  569. where_maps_to(min_i,min_j,2) == where_maps_to(max_i,min_j,2) .and. &
  570. where_maps_to(min_i,min_j,1) /= OUTSIDE_DOMAIN) then
  571. x_dest = where_maps_to(min_i,min_j,1)
  572. y_dest = where_maps_to(min_i,min_j,2)
  573. ! If this grid point was already given a value from higher-priority source data,
  574. ! there is nothing to do.
  575. if (.not. bitarray_test(processed_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  576. ! If this grid point has never been given a value by this level of source data,
  577. ! initialize the point
  578. if (.not. bitarray_test(new_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  579. do k=min_k,max_k
  580. dst_array(x_dest,y_dest,k) = 0.
  581. end do
  582. end if
  583. ! Sum all the points whose nearest neighbor is this grid point
  584. if (present(mask_array)) then
  585. do i=min_i,max_i
  586. do j=min_j,max_j
  587. do k=min_k,max_k
  588. ! Ignore masked/missing values in the source data
  589. if ((tile_array(i,j,k) /= msgval) .and. &
  590. (mask_array(i,j) /= maskval)) then
  591. dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
  592. n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
  593. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  594. end if
  595. end do
  596. end do
  597. end do
  598. else
  599. do i=min_i,max_i
  600. do j=min_j,max_j
  601. do k=min_k,max_k
  602. ! Ignore masked/missing values in the source data
  603. if (tile_array(i,j,k) /= msgval) then
  604. dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
  605. n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
  606. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  607. end if
  608. end do
  609. end do
  610. end do
  611. end if
  612. end if
  613. ! Rectangle is a square of four points, and we can simply deal with each of the points
  614. else if (((max_i - min_i + 1) <= 2) .and. ((max_j - min_j + 1) <= 2)) then
  615. do i=min_i,max_i
  616. do j=min_j,max_j
  617. x_dest = where_maps_to(i,j,1)
  618. y_dest = where_maps_to(i,j,2)
  619. if (x_dest /= OUTSIDE_DOMAIN) then
  620. if (.not. bitarray_test(processed_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  621. if (.not. bitarray_test(new_pts, x_dest-start_x+1, y_dest-start_y+1)) then
  622. do k=min_k,max_k
  623. dst_array(x_dest,y_dest,k) = 0.
  624. end do
  625. end if
  626. if (present(mask_array)) then
  627. do k=min_k,max_k
  628. ! Ignore masked/missing values
  629. if ((tile_array(i,j,k) /= msgval) .and. &
  630. (mask_array(i,j) /= maskval)) then
  631. dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
  632. n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
  633. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  634. end if
  635. end do
  636. else
  637. do k=min_k,max_k
  638. ! Ignore masked/missing values
  639. if (tile_array(i,j,k) /= msgval) then
  640. dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
  641. n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
  642. call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
  643. end if
  644. end do
  645. end if
  646. end if
  647. end if
  648. end do
  649. end do
  650. ! Not all corners map to the same grid point, and the rectangle contains more than
  651. ! four points
  652. else
  653. center_i = (max_i + min_i)/2
  654. center_j = (max_j + min_j)/2
  655. ! Recursively process lower-left rectangle
  656. call process_continuous_block(tile_array, istagger, where_maps_to, min_i, min_j, min_k, center_i, &
  657. center_j, max_k, dst_array, n, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  658. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  659. ! Recursively process lower-right rectangle
  660. if (center_i < max_i) then
  661. call process_continuous_block(tile_array, istagger, where_maps_to, center_i+1, min_j, min_k, max_i, &
  662. center_j, max_k, dst_array, n, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  663. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  664. end if
  665. ! Recursively process upper-left rectangle
  666. if (center_j < max_j) then
  667. call process_continuous_block(tile_array, istagger, where_maps_to, min_i, center_j+1, min_k, center_i, &
  668. max_j, max_k, dst_array, n, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  669. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  670. end if
  671. ! Recursively process upper-right rectangle
  672. if (center_i < max_i .and. center_j < max_j) then
  673. call process_continuous_block(tile_array, istagger, where_maps_to, center_i+1, center_j+1, min_k, max_i, &
  674. max_j, max_k, dst_array, n, start_x, end_x, start_y, end_y, start_z, end_z, processed_pts, &
  675. new_pts, ilevel, sr_x, sr_y, msgval, maskval, mask_array)
  676. end if
  677. end if
  678. end subroutine process_continuous_block
  679. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  680. ! Name: get_point
  681. !
  682. ! Purpose: For a specified lat/lon and level, return the value of the field
  683. ! interpolated to or nearest the lat/lon.
  684. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  685. function get_point(xlat, xlon, lvl, fieldname, &
  686. ilevel, interp_type, msgval)
  687. ! Modules
  688. use interp_module
  689. use llxy_module
  690. implicit none
  691. ! Arguments
  692. integer, intent(in) :: lvl, ilevel
  693. real, intent(in) :: xlat, xlon, msgval
  694. character (len=128), intent(in) :: fieldname
  695. integer, dimension(:), intent(in) :: interp_type
  696. ! Return value
  697. real :: get_point
  698. ! Local variables
  699. integer :: istatus, current_domain
  700. real :: rlat, rlon, rx, ry
  701. rlat = xlat
  702. if (xlon >= 180.) then
  703. rlon = xlon - 360.
  704. else
  705. rlon = xlon
  706. end if
  707. ! If tile is in memory, interpolate
  708. if (ilevel == src_level .and. is_point_in_tile(rlat, rlon, ilevel) .and. fieldname == src_fieldname) then
  709. current_domain = iget_selected_domain()
  710. call select_domain(SOURCE_PROJ)
  711. call lltoxy(rlat, rlon, rx, ry, M) ! Assume source data on unstaggered grid
  712. call select_domain(current_domain)
  713. get_point = interp_sequence(rx, ry, lvl, src_array, src_min_x, src_max_x, src_min_y, &
  714. src_max_y, src_min_z, src_max_z, msgval, interp_type, 1)
  715. else
  716. call get_data_tile(rlat, rlon, ilevel, fieldname, &
  717. src_fname, src_array, src_min_x, src_max_x, src_min_y, &
  718. src_max_y, src_min_z, src_max_z, src_npts_bdr, &
  719. istatus)
  720. src_fieldname = fieldname
  721. src_level = ilevel
  722. if (istatus /= 0) then
  723. get_point = msgval
  724. return
  725. end if
  726. current_domain = iget_selected_domain()
  727. call select_domain(SOURCE_PROJ)
  728. call lltoxy(rlat, rlon, rx, ry, M) ! Assume source data on unstaggered grid
  729. call select_domain(current_domain)
  730. get_point = interp_sequence(rx, ry, lvl, src_array, src_min_x, src_max_x, src_min_y, &
  731. src_max_y, src_min_z, src_max_z, msgval, interp_type, 1)
  732. end if
  733. return
  734. end function get_point
  735. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  736. ! Name: have_processed_tile
  737. !
  738. ! Purpose: This funtion returns .true. if the tile of data for
  739. ! the specified field has already been processed, and .false. otherwise.
  740. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  741. function have_processed_tile(xlat, xlon, fieldname, ilevel)
  742. implicit none
  743. ! Arguments
  744. integer, intent(in) :: ilevel
  745. real, intent(in) :: xlat, xlon
  746. character (len=128), intent(in) :: fieldname
  747. ! Return value
  748. logical :: have_processed_tile
  749. ! Local variables
  750. integer :: istatus
  751. character (len=256) :: test_fname
  752. call get_tile_fname(test_fname, xlat, xlon, ilevel, fieldname, istatus)
  753. have_processed_tile = hash_search(h_table, test_fname)
  754. return
  755. end function have_processed_tile
  756. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  757. ! Name: is_point_in_tile
  758. !
  759. ! Purpose: Returns whether the specified lat/lon could be processed
  760. ! without incurring a file access.
  761. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  762. function is_point_in_tile(xlat, xlon, ilevel)
  763. use llxy_module
  764. implicit none
  765. ! Arguments
  766. integer, intent(in) :: ilevel
  767. real, intent(in) :: xlat, xlon
  768. ! Return value
  769. logical :: is_point_in_tile
  770. ! Local variables
  771. integer :: current_domain
  772. real :: rlat, rlon, rx, ry
  773. rlat = xlat
  774. if (xlon >= 180.) then
  775. rlon = xlon - 360.
  776. else
  777. rlon = xlon
  778. end if
  779. current_domain = iget_selected_domain()
  780. call select_domain(SOURCE_PROJ)
  781. call lltoxy(rlat, rlon, rx, ry, M)
  782. call select_domain(current_domain)
  783. ! if (real(src_min_x+src_npts_bdr) <= rx .and. rx <= real(src_max_x-src_npts_bdr) .and. &
  784. ! real(src_min_y+src_npts_bdr) <= ry .and. ry <= real(src_max_y-src_npts_bdr)) then
  785. ! BUG 2006-06-01
  786. ! if (src_min_x+src_npts_bdr <= ceiling(rx) .and. floor(rx) <= src_max_x-src_npts_bdr .and. &
  787. ! src_min_y+src_npts_bdr <= ceiling(ry) .and. floor(ry) <= src_max_y-src_npts_bdr) then
  788. if (src_min_x+src_npts_bdr <= floor(rx+0.5) .and. ceiling(rx-0.5) <= src_max_x-src_npts_bdr .and. &
  789. src_min_y+src_npts_bdr <= floor(ry+0.5) .and. ceiling(ry-0.5) <= src_max_y-src_npts_bdr) then
  790. is_point_in_tile = .true.
  791. else
  792. is_point_in_tile = .false.
  793. end if
  794. return
  795. end function is_point_in_tile
  796. end module proc_point_module