PageRenderTime 50ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/WPS/geogrid/src/process_tile_module.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 2084 lines | 1265 code | 310 blank | 509 comment | 366 complexity | 039d3d2e0118ec2527dcd4f13fac8fbe MD5 | raw file
Possible License(s): AGPL-1.0
  1. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. ! Module: process_tile
  3. !
  4. ! Description:
  5. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  6. module process_tile_module
  7. use module_debug
  8. contains
  9. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  10. ! Name: process_tile
  11. !
  12. ! Purpose: To process a tile, whose lower-left corner is at
  13. ! (tile_i_min, tile_j_min) and whose upper-right corner is at
  14. ! (tile_i_max, tile_j_max), of the model grid given by which_domain
  15. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  16. subroutine process_tile(which_domain, grid_type, dynopt, &
  17. dummy_start_dom_i, dummy_end_dom_i, &
  18. dummy_start_dom_j, dummy_end_dom_j, &
  19. dummy_start_patch_i, dummy_end_patch_i, &
  20. dummy_start_patch_j, dummy_end_patch_j, &
  21. extra_col, extra_row)
  22. use bitarray_module
  23. use hash_module
  24. use llxy_module
  25. use misc_definitions_module
  26. use output_module
  27. use smooth_module
  28. use source_data_module
  29. use gridinfo_module, only : subgrid_ratio_x, subgrid_ratio_y
  30. implicit none
  31. ! Arguments
  32. integer, intent(in) :: which_domain, dynopt, &
  33. dummy_start_dom_i, dummy_end_dom_i, dummy_start_dom_j, dummy_end_dom_j, &
  34. dummy_start_patch_i, dummy_end_patch_i, dummy_start_patch_j, dummy_end_patch_j
  35. logical, intent(in) :: extra_col, extra_row
  36. character (len=1), intent(in) :: grid_type
  37. ! Local variables
  38. integer :: i, j, k, kk, istatus, ifieldstatus, idomcatstatus, field_count
  39. integer :: min_category, max_category, min_level, max_level, &
  40. smth_opt, smth_passes, num_landmask_categories
  41. integer :: start_dom_i, end_dom_i, start_dom_j, end_dom_j, end_dom_stag_i, end_dom_stag_j
  42. integer :: start_patch_i, end_patch_i, start_patch_j, end_patch_j, end_patch_stag_i, end_patch_stag_j
  43. integer :: start_mem_i, end_mem_i, start_mem_j, end_mem_j, end_mem_stag_i, end_mem_stag_j
  44. integer :: start_mem_sub_i, end_mem_sub_i, start_mem_sub_j, end_mem_sub_j
  45. integer :: sm1, em1, sm2, em2
  46. integer :: istagger
  47. integer, dimension(MAX_LANDMASK_CATEGORIES) :: landmask_value
  48. real :: sum, dominant, msg_fill_val, topo_flag_val, mass_flag, land_total, water_total
  49. real, dimension(16) :: corner_lats, corner_lons
  50. real, pointer, dimension(:,:) :: xlat_array, xlon_array, &
  51. xlat_array_u, xlon_array_u, &
  52. xlat_array_v, xlon_array_v, &
  53. clat_array, clon_array, &
  54. xlat_array_subgrid, xlon_array_subgrid, &
  55. f_array, e_array, &
  56. mapfac_array_m_x, mapfac_array_u_x, mapfac_array_v_x, &
  57. mapfac_array_m_y, mapfac_array_u_y, mapfac_array_v_y, &
  58. mapfac_array_x_subgrid, mapfac_array_y_subgrid, &
  59. sina_array, cosa_array
  60. real, pointer, dimension(:,:) :: xlat_ptr, xlon_ptr, mapfac_ptr_x, mapfac_ptr_y, landmask, dominant_field
  61. real, pointer, dimension(:,:,:) :: field, slp_field
  62. logical :: is_water_mask, only_save_dominant, halt_on_missing
  63. character (len=19) :: datestr
  64. character (len=128) :: fieldname, gradname, domname, landmask_name
  65. character (len=256) :: temp_string
  66. type (bitarray) :: processed_domain
  67. type (hashtable) :: processed_fieldnames
  68. character (len=128), dimension(2) :: dimnames
  69. integer :: sr_x, sr_y
  70. logical :: subgrid_var
  71. sr_x=subgrid_ratio_x(which_domain)
  72. sr_y=subgrid_ratio_y(which_domain)
  73. datestr = '0000-00-00_00:00:00'
  74. field_count = 0
  75. mass_flag=1.0
  76. ! The following pertains primarily to the C grid
  77. ! Determine whether only (n-1)th rows/columns should be computed for variables
  78. ! on staggered grid. In a distributed memory situation, not every tile should
  79. ! have only (n-1)th rows/columns computed, or we end up with (n-k)
  80. ! rows/columns when there are k patches in the y/x direction
  81. if (extra_col) then
  82. start_patch_i = dummy_start_patch_i ! The seemingly pointless renaming of start
  83. end_patch_i = dummy_end_patch_i - 1 ! naming convention with modified end_patch variables,
  84. end_patch_stag_i = dummy_end_patch_i ! variables is so that we can maintain consistent
  85. ! which are marked as intent(in)
  86. start_mem_i = start_patch_i - HALO_WIDTH
  87. end_mem_i = end_patch_i + HALO_WIDTH
  88. end_mem_stag_i = end_patch_stag_i + HALO_WIDTH
  89. else
  90. start_patch_i = dummy_start_patch_i
  91. end_patch_i = dummy_end_patch_i
  92. end_patch_stag_i = dummy_end_patch_i
  93. start_mem_i = start_patch_i - HALO_WIDTH
  94. end_mem_i = end_patch_i + HALO_WIDTH
  95. end_mem_stag_i = end_patch_stag_i + HALO_WIDTH
  96. end if
  97. if (extra_row) then
  98. start_patch_j = dummy_start_patch_j
  99. end_patch_j = dummy_end_patch_j - 1
  100. end_patch_stag_j = dummy_end_patch_j
  101. start_mem_j = start_patch_j - HALO_WIDTH
  102. end_mem_j = end_patch_j + HALO_WIDTH
  103. end_mem_stag_j = end_patch_stag_j + HALO_WIDTH
  104. else
  105. start_patch_j = dummy_start_patch_j
  106. end_patch_j = dummy_end_patch_j
  107. end_patch_stag_j = dummy_end_patch_j
  108. start_mem_j = start_patch_j - HALO_WIDTH
  109. end_mem_j = end_patch_j + HALO_WIDTH
  110. end_mem_stag_j = end_patch_stag_j + HALO_WIDTH
  111. end if
  112. start_dom_i = dummy_start_dom_i
  113. if (grid_type == 'C') then
  114. end_dom_i = dummy_end_dom_i - 1
  115. end_dom_stag_i = dummy_end_dom_i
  116. else if (grid_type == 'E') then
  117. end_dom_i = dummy_end_dom_i
  118. end_dom_stag_i = dummy_end_dom_i
  119. end if
  120. start_dom_j = dummy_start_dom_j
  121. if (grid_type == 'C') then
  122. end_dom_j = dummy_end_dom_j - 1
  123. end_dom_stag_j = dummy_end_dom_j
  124. else if (grid_type == 'E') then
  125. end_dom_j = dummy_end_dom_j
  126. end_dom_stag_j = dummy_end_dom_j
  127. end if
  128. start_mem_sub_i = (start_mem_i - 1 ) * sr_x + 1
  129. if(.not.extra_col)then
  130. end_mem_sub_i = (end_mem_i) * sr_x
  131. else
  132. end_mem_sub_i = (end_mem_i + 1) * sr_x
  133. end if
  134. start_mem_sub_j = (start_mem_j -1 ) * sr_y + 1
  135. if(.not.extra_row)then
  136. end_mem_sub_j = (end_mem_j) * sr_y
  137. else
  138. end_mem_sub_j = (end_mem_j + 1) * sr_y
  139. end if
  140. ! Allocate arrays to hold all lat/lon fields; these will persist for the duration of
  141. ! the process_tile routine
  142. ! For C grid, we have M, U, and V points
  143. ! For E grid, we have only M and V points
  144. allocate(xlat_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  145. allocate(xlon_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  146. allocate(xlat_array_v(start_mem_i:end_mem_i, start_mem_j:end_mem_stag_j))
  147. allocate(xlon_array_v(start_mem_i:end_mem_i, start_mem_j:end_mem_stag_j))
  148. if (grid_type == 'C') then
  149. allocate(xlat_array_u(start_mem_i:end_mem_stag_i, start_mem_j:end_mem_j))
  150. allocate(xlon_array_u(start_mem_i:end_mem_stag_i, start_mem_j:end_mem_j))
  151. allocate(clat_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  152. allocate(clon_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  153. allocate(xlat_array_subgrid(start_mem_sub_i:end_mem_sub_i,start_mem_sub_j:end_mem_sub_j))
  154. allocate(xlon_array_subgrid(start_mem_sub_i:end_mem_sub_i,start_mem_sub_j:end_mem_sub_j))
  155. allocate(mapfac_array_x_subgrid(start_mem_sub_i:end_mem_sub_i,start_mem_sub_j:end_mem_sub_j))
  156. allocate(mapfac_array_y_subgrid(start_mem_sub_i:end_mem_sub_i,start_mem_sub_j:end_mem_sub_j))
  157. end if
  158. ! Initialize hash table to track which fields have been processed
  159. call hash_init(processed_fieldnames)
  160. !
  161. ! Calculate lat/lon for every point in the tile (XLAT and XLON)
  162. ! The xlat_array and xlon_array arrays will be used in processing other fields
  163. !
  164. call mprintf(.true.,STDOUT,' Processing XLAT and XLONG')
  165. if (grid_type == 'C') then
  166. call get_lat_lon_fields(xlat_array, xlon_array, start_mem_i, &
  167. start_mem_j, end_mem_i, end_mem_j, M)
  168. call get_lat_lon_fields(xlat_array_v, xlon_array_v, start_mem_i, &
  169. start_mem_j, end_mem_i, end_mem_stag_j, V)
  170. call get_lat_lon_fields(xlat_array_u, xlon_array_u, start_mem_i, &
  171. start_mem_j, end_mem_stag_i, end_mem_j, U)
  172. call get_lat_lon_fields(clat_array, clon_array, start_mem_i, &
  173. start_mem_j, end_mem_i, end_mem_j, M, comp_ll=.true.)
  174. call get_lat_lon_fields(xlat_array_subgrid, xlon_array_subgrid, &
  175. start_mem_sub_i, start_mem_sub_j, end_mem_sub_i, end_mem_sub_j, M, sub_x=sr_x, sub_y=sr_y)
  176. call get_map_factor(xlat_array_subgrid, xlon_array_subgrid, mapfac_array_x_subgrid, &
  177. mapfac_array_y_subgrid, start_mem_sub_i, start_mem_sub_j, end_mem_sub_i, end_mem_sub_j)
  178. corner_lats(1) = xlat_array(start_patch_i,start_patch_j)
  179. corner_lats(2) = xlat_array(start_patch_i,end_patch_j)
  180. corner_lats(3) = xlat_array(end_patch_i,end_patch_j)
  181. corner_lats(4) = xlat_array(end_patch_i,start_patch_j)
  182. corner_lats(5) = xlat_array_u(start_patch_i,start_patch_j)
  183. corner_lats(6) = xlat_array_u(start_patch_i,end_patch_j)
  184. corner_lats(7) = xlat_array_u(end_patch_stag_i,end_patch_j)
  185. corner_lats(8) = xlat_array_u(end_patch_stag_i,start_patch_j)
  186. corner_lats(9) = xlat_array_v(start_patch_i,start_patch_j)
  187. corner_lats(10) = xlat_array_v(start_patch_i,end_patch_stag_j)
  188. corner_lats(11) = xlat_array_v(end_patch_i,end_patch_stag_j)
  189. corner_lats(12) = xlat_array_v(end_patch_i,start_patch_j)
  190. call xytoll(real(start_patch_i)-0.5, real(start_patch_j)-0.5, corner_lats(13), corner_lons(13), M)
  191. call xytoll(real(start_patch_i)-0.5, real(end_patch_j)+0.5, corner_lats(14), corner_lons(14), M)
  192. call xytoll(real(end_patch_i)+0.5, real(end_patch_j)+0.5, corner_lats(15), corner_lons(15), M)
  193. call xytoll(real(end_patch_i)+0.5, real(start_patch_j)-0.5, corner_lats(16), corner_lons(16), M)
  194. corner_lons(1) = xlon_array(start_patch_i,start_patch_j)
  195. corner_lons(2) = xlon_array(start_patch_i,end_patch_j)
  196. corner_lons(3) = xlon_array(end_patch_i,end_patch_j)
  197. corner_lons(4) = xlon_array(end_patch_i,start_patch_j)
  198. corner_lons(5) = xlon_array_u(start_patch_i,start_patch_j)
  199. corner_lons(6) = xlon_array_u(start_patch_i,end_patch_j)
  200. corner_lons(7) = xlon_array_u(end_patch_stag_i,end_patch_j)
  201. corner_lons(8) = xlon_array_u(end_patch_stag_i,start_patch_j)
  202. corner_lons(9) = xlon_array_v(start_patch_i,start_patch_j)
  203. corner_lons(10) = xlon_array_v(start_patch_i,end_patch_stag_j)
  204. corner_lons(11) = xlon_array_v(end_patch_i,end_patch_stag_j)
  205. corner_lons(12) = xlon_array_v(end_patch_i,start_patch_j)
  206. else if (grid_type == 'E') then
  207. call get_lat_lon_fields(xlat_array, xlon_array, start_mem_i, &
  208. start_mem_j, end_mem_i, end_mem_j, HH)
  209. call get_lat_lon_fields(xlat_array_v, xlon_array_v, start_mem_i, &
  210. start_mem_j, end_mem_i, end_mem_stag_j, VV)
  211. corner_lats(1) = xlat_array(start_patch_i,start_patch_j)
  212. corner_lats(2) = xlat_array(start_patch_i,end_patch_j)
  213. corner_lats(3) = xlat_array(end_patch_i,end_patch_j)
  214. corner_lats(4) = xlat_array(end_patch_i,start_patch_j)
  215. corner_lats(5) = xlat_array_v(start_patch_i,start_patch_j)
  216. corner_lats(6) = xlat_array_v(start_patch_i,end_patch_stag_j)
  217. corner_lats(7) = xlat_array_v(end_patch_i,end_patch_stag_j)
  218. corner_lats(8) = xlat_array_v(end_patch_i,start_patch_j)
  219. corner_lats(9) = 0.0
  220. corner_lats(10) = 0.0
  221. corner_lats(11) = 0.0
  222. corner_lats(12) = 0.0
  223. corner_lats(13) = 0.0
  224. corner_lats(14) = 0.0
  225. corner_lats(15) = 0.0
  226. corner_lats(16) = 0.0
  227. corner_lons(1) = xlon_array(start_patch_i,start_patch_j)
  228. corner_lons(2) = xlon_array(start_patch_i,end_patch_j)
  229. corner_lons(3) = xlon_array(end_patch_i,end_patch_j)
  230. corner_lons(4) = xlon_array(end_patch_i,start_patch_j)
  231. corner_lons(5) = xlon_array_v(start_patch_i,start_patch_j)
  232. corner_lons(6) = xlon_array_v(start_patch_i,end_patch_stag_j)
  233. corner_lons(7) = xlon_array_v(end_patch_i,end_patch_stag_j)
  234. corner_lons(8) = xlon_array_v(end_patch_i,start_patch_j)
  235. corner_lons(9) = 0.0
  236. corner_lons(10) = 0.0
  237. corner_lons(11) = 0.0
  238. corner_lons(12) = 0.0
  239. corner_lons(13) = 0.0
  240. corner_lons(14) = 0.0
  241. corner_lons(15) = 0.0
  242. corner_lons(16) = 0.0
  243. end if
  244. ! Initialize the output module now that we have the corner point lats/lons
  245. call output_init(which_domain, 'OUTPUT FROM GEOGRID V3.3', '0000-00-00_00:00:00', grid_type, dynopt, &
  246. corner_lats, corner_lons, &
  247. start_dom_i, end_dom_i, start_dom_j, end_dom_j, &
  248. start_patch_i, end_patch_i, start_patch_j, end_patch_j, &
  249. start_mem_i, end_mem_i, start_mem_j, end_mem_j, &
  250. extra_col, extra_row)
  251. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, &
  252. 'XLAT_M', datestr, real_array = xlat_array)
  253. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, &
  254. 'XLONG_M', datestr, real_array = xlon_array)
  255. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_stag_j, 1, 1, &
  256. 'XLAT_V', datestr, real_array = xlat_array_v)
  257. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_stag_j, 1, 1, &
  258. 'XLONG_V', datestr, real_array = xlon_array_v)
  259. if (grid_type == 'C') then
  260. call write_field(start_mem_i, end_mem_stag_i, start_mem_j, end_mem_j, 1, 1, &
  261. 'XLAT_U', datestr, real_array = xlat_array_u)
  262. call write_field(start_mem_i, end_mem_stag_i, start_mem_j, end_mem_j, 1, 1, &
  263. 'XLONG_U', datestr, real_array = xlon_array_u)
  264. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, &
  265. 'CLAT', datestr, real_array = clat_array)
  266. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, &
  267. 'CLONG', datestr, real_array = clon_array)
  268. call write_field(start_mem_sub_i, end_mem_sub_i, start_mem_sub_j, end_mem_sub_j, 1, 1, &
  269. 'FXLAT', datestr, real_array = xlat_array_subgrid)
  270. call write_field(start_mem_sub_i, end_mem_sub_i, start_mem_sub_j, end_mem_sub_j, 1, 1, &
  271. 'FXLONG', datestr, real_array = xlon_array_subgrid)
  272. if (associated(clat_array)) deallocate(clat_array)
  273. if (associated(clon_array)) deallocate(clon_array)
  274. end if
  275. !
  276. ! Calculate map factor for current domain
  277. !
  278. if (grid_type == 'C') then
  279. call mprintf(.true.,STDOUT,' Processing MAPFAC')
  280. allocate(mapfac_array_m_x(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  281. allocate(mapfac_array_m_y(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  282. call get_map_factor(xlat_array, xlon_array, mapfac_array_m_x, mapfac_array_m_y, start_mem_i, &
  283. start_mem_j, end_mem_i, end_mem_j)
  284. ! Global WRF uses map scale factors in X and Y directions, but "regular" WRF uses a single MSF
  285. ! on each staggering. In the case of regular WRF, we can assume that MAPFAC_MX = MAPFAC_MY = MAPFAC_M,
  286. ! and so we can simply write MAPFAC_MX as the MAPFAC_M field. Ultimately, when global WRF is
  287. ! merged into the WRF trunk, we will need only two map scale factor fields for each staggering,
  288. ! in the x and y directions, and these will be the same in the case of non-Cassini projections
  289. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'MAPFAC_M', &
  290. datestr, real_array = mapfac_array_m_x)
  291. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'MAPFAC_MX', &
  292. datestr, real_array = mapfac_array_m_x)
  293. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'MAPFAC_MY', &
  294. datestr, real_array = mapfac_array_m_y)
  295. allocate(mapfac_array_v_x(start_mem_i:end_mem_i, start_mem_j:end_mem_stag_j))
  296. allocate(mapfac_array_v_y(start_mem_i:end_mem_i, start_mem_j:end_mem_stag_j))
  297. call get_map_factor(xlat_array_v, xlon_array_v, mapfac_array_v_x, mapfac_array_v_y, start_mem_i, &
  298. start_mem_j, end_mem_i, end_mem_stag_j)
  299. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_stag_j, 1, 1, 'MAPFAC_V', &
  300. datestr, real_array = mapfac_array_v_x)
  301. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_stag_j, 1, 1, 'MAPFAC_VX', &
  302. datestr, real_array = mapfac_array_v_x)
  303. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_stag_j, 1, 1, 'MAPFAC_VY', &
  304. datestr, real_array = mapfac_array_v_y)
  305. allocate(mapfac_array_u_x(start_mem_i:end_mem_stag_i, start_mem_j:end_mem_j))
  306. allocate(mapfac_array_u_y(start_mem_i:end_mem_stag_i, start_mem_j:end_mem_j))
  307. call get_map_factor(xlat_array_u, xlon_array_u, mapfac_array_u_x, mapfac_array_u_y, start_mem_i, &
  308. start_mem_j, end_mem_stag_i, end_mem_j)
  309. call write_field(start_mem_i, end_mem_stag_i, start_mem_j, end_mem_j, 1, 1, 'MAPFAC_U', &
  310. datestr, real_array = mapfac_array_u_x)
  311. call write_field(start_mem_i, end_mem_stag_i, start_mem_j, end_mem_j, 1, 1, 'MAPFAC_UX', &
  312. datestr, real_array = mapfac_array_u_x)
  313. call write_field(start_mem_i, end_mem_stag_i, start_mem_j, end_mem_j, 1, 1, 'MAPFAC_UY', &
  314. datestr, real_array = mapfac_array_u_y)
  315. end if
  316. !
  317. ! Coriolis parameters (E and F)
  318. !
  319. call mprintf(.true.,STDOUT,' Processing F and E')
  320. allocate(f_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  321. allocate(e_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  322. call get_coriolis_parameters(xlat_array, f_array, e_array, &
  323. start_mem_i, start_mem_j, end_mem_i, end_mem_j)
  324. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'E', &
  325. datestr, real_array = e_array)
  326. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'F', &
  327. datestr, real_array = f_array)
  328. if (associated(f_array)) deallocate(f_array)
  329. if (associated(e_array)) deallocate(e_array)
  330. !
  331. ! Rotation angle (SINALPHA and COSALPHA)
  332. !
  333. if (grid_type == 'C') then
  334. call mprintf(.true.,STDOUT,' Processing ROTANG')
  335. allocate(sina_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  336. allocate(cosa_array(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  337. call get_rotang(xlat_array, xlon_array, cosa_array, sina_array, &
  338. start_mem_i, start_mem_j, end_mem_i, end_mem_j)
  339. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'SINALPHA', &
  340. datestr, real_array = sina_array)
  341. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'COSALPHA', &
  342. datestr, real_array = cosa_array)
  343. if (associated(sina_array)) deallocate(sina_array)
  344. if (associated(cosa_array)) deallocate(cosa_array)
  345. end if
  346. ! Every field up until now should probably just be processed regardless of what the user
  347. ! has specified for fields to be processed.
  348. ! Hereafter, we process user-specified fields
  349. !
  350. ! First process the field that we will derive a landmask from
  351. !
  352. call get_landmask_field(geog_data_res(which_domain), landmask_name, is_water_mask, landmask_value, istatus)
  353. do kk=1,MAX_LANDMASK_CATEGORIES
  354. if (landmask_value(kk) == INVALID) then
  355. num_landmask_categories = kk-1
  356. exit
  357. end if
  358. end do
  359. if (kk > MAX_LANDMASK_CATEGORIES) num_landmask_categories = MAX_LANDMASK_CATEGORIES
  360. if (istatus /= 0) then
  361. call mprintf(.true.,WARN,'No field specified for landmask calculation. Will set landmask=1 at every grid point.')
  362. allocate(landmask(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  363. landmask = 1.
  364. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'LANDMASK', &
  365. datestr, landmask)
  366. else
  367. allocate(landmask(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  368. landmask = 1.
  369. call mprintf(.true.,STDOUT,' Processing %s', s1=trim(landmask_name))
  370. call get_missing_fill_value(landmask_name, msg_fill_val, istatus)
  371. if (istatus /= 0) msg_fill_val = NAN
  372. call get_halt_on_missing(landmask_name, halt_on_missing, istatus)
  373. if (istatus /= 0) halt_on_missing = .false.
  374. ! Do we calculate a dominant category for this field?
  375. call get_domcategory_name(landmask_name, domname, only_save_dominant, idomcatstatus)
  376. temp_string = ' '
  377. temp_string(1:128) = landmask_name
  378. call hash_insert(processed_fieldnames, temp_string)
  379. call get_max_categories(landmask_name, min_category, max_category, istatus)
  380. allocate(field(start_mem_i:end_mem_i, start_mem_j:end_mem_j, min_category:max_category))
  381. if (.not. only_save_dominant) then
  382. field_count = field_count + 1
  383. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  384. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=landmask_name)
  385. else
  386. field_count = field_count + 1
  387. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  388. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=domname)
  389. end if
  390. if (grid_type == 'C') then
  391. call calc_field(landmask_name, field, xlat_array, xlon_array, M, &
  392. start_mem_i, end_mem_i, start_mem_j, end_mem_j, &
  393. min_category, max_category, processed_domain, 1, landmask=landmask, sr_x=1, sr_y=1)
  394. else if (grid_type == 'E') then
  395. call calc_field(landmask_name, field, xlat_array, xlon_array, HH, &
  396. start_mem_i, end_mem_i, start_mem_j, end_mem_j, &
  397. min_category, max_category, processed_domain, 1, landmask=landmask, sr_x=1, sr_y=1)
  398. end if
  399. ! Find fractions
  400. do i=start_mem_i, end_mem_i
  401. do j=start_mem_j, end_mem_j
  402. sum = 0.
  403. do k=min_category,max_category
  404. sum = sum + field(i,j,k)
  405. end do
  406. if (sum > 0.0) then
  407. do k=min_category,max_category
  408. field(i,j,k) = field(i,j,k) / sum
  409. end do
  410. else
  411. do k=min_category,max_category
  412. field(i,j,k) = msg_fill_val
  413. end do
  414. end if
  415. end do
  416. end do
  417. ! If user wants to halt when a missing value is found in output field, check now
  418. if (halt_on_missing) then
  419. do i=start_mem_i, end_mem_i
  420. do j=start_mem_j, end_mem_j
  421. ! Only need to examine k=1
  422. if (field(i,j,1) == msg_fill_val) then
  423. call mprintf(.true.,ERROR,' Missing value encountered in output field. Quitting.')
  424. end if
  425. end do
  426. end do
  427. end if
  428. if (is_water_mask) then
  429. call mprintf(.true.,STDOUT,' Calculating landmask from %s ( WATER =', &
  430. newline=.false.,s1=trim(landmask_name))
  431. else
  432. call mprintf(.true.,STDOUT,' Calculating landmask from %s ( LAND =', &
  433. newline=.false.,s1=trim(landmask_name))
  434. end if
  435. do k = 1, num_landmask_categories
  436. call mprintf(.true.,STDOUT,' %i',newline=.false.,i1=landmask_value(k))
  437. if (k == num_landmask_categories) call mprintf(.true.,STDOUT,')')
  438. end do
  439. ! Calculate landmask
  440. if (is_water_mask) then
  441. do i=start_mem_i, end_mem_i
  442. do j=start_mem_j, end_mem_j
  443. water_total = -1.
  444. do k=1,num_landmask_categories
  445. if (landmask_value(k) >= min_category .and. landmask_value(k) <= max_category) then
  446. if (field(i,j,landmask_value(k)) /= msg_fill_val) then
  447. if (water_total < 0.) water_total = 0.
  448. water_total = water_total + field(i,j,landmask_value(k))
  449. else
  450. water_total = -1.
  451. exit
  452. end if
  453. end if
  454. end do
  455. if (water_total >= 0.0) then
  456. if (water_total < 0.50) then
  457. landmask(i,j) = 1.
  458. else
  459. landmask(i,j) = 0.
  460. end if
  461. else
  462. landmask(i,j) = -1.
  463. end if
  464. end do
  465. end do
  466. else
  467. do i=start_mem_i, end_mem_i
  468. do j=start_mem_j, end_mem_j
  469. land_total = -1.
  470. do k=1,num_landmask_categories
  471. if (landmask_value(k) >= min_category .and. landmask_value(k) <= max_category) then
  472. if (field(i,j,landmask_value(k)) /= msg_fill_val) then
  473. if (land_total < 0.) land_total = 0.
  474. land_total = land_total + field(i,j,landmask_value(k))
  475. else
  476. land_total = -1.
  477. exit
  478. end if
  479. end if
  480. end do
  481. if (land_total >= 0.0) then
  482. if (land_total > 0.50) then
  483. landmask(i,j) = 1.
  484. else
  485. landmask(i,j) = 0.
  486. end if
  487. else
  488. landmask(i,j) = -1.
  489. end if
  490. end do
  491. end do
  492. end if
  493. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, 'LANDMASK', &
  494. datestr, landmask)
  495. ! If we should only save the dominant category, then no need to write out fractional field
  496. if (.not.only_save_dominant .or. (idomcatstatus /= 0)) then
  497. ! Finally, we may be asked to smooth the fractional field
  498. call get_smooth_option(landmask_name, smth_opt, smth_passes, istatus)
  499. if (istatus == 0) then
  500. if (grid_type == 'C') then
  501. if (smth_opt == ONETWOONE) then
  502. call one_two_one(field, &
  503. start_patch_i, end_patch_i, &
  504. start_patch_j, end_patch_j, &
  505. start_mem_i, end_mem_i, &
  506. start_mem_j, end_mem_j, &
  507. min_category, max_category, &
  508. smth_passes, msg_fill_val)
  509. else if (smth_opt == SMTHDESMTH) then
  510. call smth_desmth(field, &
  511. start_patch_i, end_patch_i, &
  512. start_patch_j, end_patch_j, &
  513. start_mem_i, end_mem_i, &
  514. start_mem_j, end_mem_j, &
  515. min_category, max_category, &
  516. smth_passes, msg_fill_val)
  517. else if (smth_opt == SMTHDESMTH_SPECIAL) then
  518. call smth_desmth_special(field, &
  519. start_patch_i, end_patch_i, &
  520. start_patch_j, end_patch_j, &
  521. start_mem_i, end_mem_i, &
  522. start_mem_j, end_mem_j, &
  523. min_category, max_category, &
  524. smth_passes, msg_fill_val)
  525. end if
  526. else if (grid_type == 'E') then
  527. if (smth_opt == ONETWOONE) then
  528. call one_two_one_egrid(field, &
  529. start_patch_i, end_patch_i, &
  530. start_patch_j, end_patch_j, &
  531. start_mem_i, end_mem_i, &
  532. start_mem_j, end_mem_j, &
  533. min_category, max_category, &
  534. smth_passes, msg_fill_val, 1.0)
  535. else if (smth_opt == SMTHDESMTH) then
  536. call smth_desmth_egrid(field, &
  537. start_patch_i, end_patch_i, &
  538. start_patch_j, end_patch_j, &
  539. start_mem_i, end_mem_i, &
  540. start_mem_j, end_mem_j, &
  541. min_category, max_category, &
  542. smth_passes, msg_fill_val, 1.0)
  543. else if (smth_opt == SMTHDESMTH_SPECIAL) then
  544. call mprintf(.true.,WARN,'smth-desmth_special is not currently implemented for NMM. '// &
  545. 'No smoothing will be done.')
  546. end if
  547. end if
  548. end if
  549. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, &
  550. min_category, max_category, trim(landmask_name), &
  551. datestr, real_array=field)
  552. end if
  553. if (idomcatstatus == 0) then
  554. allocate(dominant_field(start_mem_i:end_mem_i, start_mem_j:end_mem_j))
  555. if (.not. only_save_dominant) then
  556. field_count = field_count + 1
  557. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  558. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=domname)
  559. end if
  560. do i=start_mem_i, end_mem_i
  561. do j=start_mem_j, end_mem_j
  562. if ((landmask(i,j) == 1. .and. is_water_mask) .or. &
  563. (landmask(i,j) == 0. .and. .not.is_water_mask)) then
  564. dominant = 0.
  565. dominant_field(i,j) = real(min_category-1)
  566. do k=min_category,max_category
  567. do kk=1,num_landmask_categories
  568. if (k == landmask_value(kk)) exit
  569. end do
  570. if (field(i,j,k) > dominant .and. kk > num_landmask_categories) then
  571. dominant_field(i,j) = real(k)
  572. dominant = field(i,j,k)
  573. end if
  574. end do
  575. else
  576. dominant = 0.
  577. dominant_field(i,j) = real(min_category-1)
  578. do k=min_category,max_category
  579. do kk=1,num_landmask_categories
  580. if (field(i,j,k) > dominant .and. k == landmask_value(kk)) then
  581. dominant_field(i,j) = real(k)
  582. dominant = field(i,j,k)
  583. end if
  584. end do
  585. end do
  586. end if
  587. end do
  588. end do
  589. call write_field(start_mem_i, end_mem_i, start_mem_j, end_mem_j, 1, 1, trim(domname), &
  590. datestr, dominant_field)
  591. deallocate(dominant_field)
  592. end if
  593. deallocate(field)
  594. end if
  595. !
  596. ! Now process all other fields specified by the user
  597. !
  598. call reset_next_field()
  599. ifieldstatus = 0
  600. do while (ifieldstatus == 0)
  601. call get_next_fieldname(fieldname, ifieldstatus)
  602. ! There is another field in the GEOGRID.TBL file
  603. if (ifieldstatus == 0) then
  604. temp_string(1:128) = fieldname
  605. ! If this field is still to be processed
  606. if (.not. hash_search(processed_fieldnames, temp_string)) then
  607. call hash_insert(processed_fieldnames, temp_string)
  608. call mprintf(.true.,STDOUT,' Processing %s', s1=trim(fieldname))
  609. call get_output_stagger(fieldname, istagger, istatus)
  610. dimnames(:) = 'null'
  611. subgrid_var=is_subgrid_var(fieldname)
  612. if( subgrid_var ) call get_subgrid_dim_name(dimnames)
  613. if (istagger == M .and. .not. subgrid_var ) then
  614. sm1 = start_mem_i
  615. em1 = end_mem_i
  616. sm2 = start_mem_j
  617. em2 = end_mem_j
  618. xlat_ptr => xlat_array
  619. xlon_ptr => xlon_array
  620. mapfac_ptr_x => mapfac_array_m_x
  621. mapfac_ptr_y => mapfac_array_m_y
  622. else if ( subgrid_var ) then
  623. sm1 = start_mem_sub_i
  624. em1 = end_mem_sub_i
  625. sm2 = start_mem_sub_j
  626. em2 = end_mem_sub_j
  627. xlat_ptr => xlat_array_subgrid
  628. xlon_ptr => xlon_array_subgrid
  629. mapfac_ptr_x => mapfac_array_x_subgrid
  630. mapfac_ptr_y => mapfac_array_y_subgrid
  631. else if (istagger == U) then ! In the case that extra_cols = .false.
  632. sm1 = start_mem_i ! we should have that end_mem_stag is
  633. em1 = end_mem_stag_i ! the same as end_mem, so we do not need
  634. sm2 = start_mem_j ! to check extra_cols or extra rows here
  635. em2 = end_mem_j
  636. xlat_ptr => xlat_array_u
  637. xlon_ptr => xlon_array_u
  638. mapfac_ptr_x => mapfac_array_u_x
  639. mapfac_ptr_y => mapfac_array_u_y
  640. else if (istagger == V) then
  641. sm1 = start_mem_i
  642. em1 = end_mem_i
  643. sm2 = start_mem_j
  644. em2 = end_mem_stag_j
  645. xlat_ptr => xlat_array_v
  646. xlon_ptr => xlon_array_v
  647. mapfac_ptr_x => mapfac_array_v_x
  648. mapfac_ptr_y => mapfac_array_v_y
  649. else if (istagger == HH) then ! E grid
  650. sm1 = start_mem_i
  651. em1 = end_mem_i
  652. sm2 = start_mem_j
  653. em2 = end_mem_j
  654. xlat_ptr => xlat_array
  655. xlon_ptr => xlon_array
  656. mapfac_ptr_x => mapfac_array_m_x
  657. mapfac_ptr_y => mapfac_array_m_y
  658. else if (istagger == VV) then ! E grid
  659. sm1 = start_mem_i
  660. em1 = end_mem_i
  661. sm2 = start_mem_j
  662. em2 = end_mem_stag_j
  663. xlat_ptr => xlat_array_v
  664. xlon_ptr => xlon_array_v
  665. mapfac_ptr_x => mapfac_array_v_x
  666. mapfac_ptr_y => mapfac_array_v_y
  667. end if
  668. call get_missing_fill_value(fieldname, msg_fill_val, istatus)
  669. if (istatus /= 0) msg_fill_val = NAN
  670. call get_halt_on_missing(fieldname, halt_on_missing, istatus)
  671. if (istatus /= 0) halt_on_missing = .false.
  672. ! Destination field type is CONTINUOUS
  673. if (iget_fieldtype(fieldname,istatus) == CONTINUOUS) then
  674. call get_max_levels(fieldname, min_level, max_level, istatus)
  675. allocate(field(sm1:em1, sm2:em2, min_level:max_level))
  676. field_count = field_count + 1
  677. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  678. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=fieldname)
  679. if ( subgrid_var ) then
  680. call calc_field(fieldname, field, xlat_ptr, xlon_ptr, istagger, &
  681. sm1, em1, sm2, em2, min_level, max_level, &
  682. processed_domain, 1, sr_x=sr_x, sr_y=sr_y)
  683. else
  684. call calc_field(fieldname, field, xlat_ptr, xlon_ptr, istagger, &
  685. sm1, em1, sm2, em2, min_level, max_level, &
  686. processed_domain, 1, landmask=landmask)
  687. end if
  688. ! If user wants to halt when a missing value is found in output field, check now
  689. if (halt_on_missing) then
  690. do i=sm1, em1
  691. do j=sm2, em2
  692. ! Only need to examine k=1
  693. if (field(i,j,1) == msg_fill_val) then
  694. call mprintf(.true.,ERROR,' Missing value encountered in output field. Quitting.')
  695. end if
  696. end do
  697. end do
  698. end if
  699. ! We may be asked to smooth the fractional field
  700. call get_smooth_option(fieldname, smth_opt, smth_passes, istatus)
  701. if (istatus == 0) then
  702. if (grid_type == 'C') then
  703. if (smth_opt == ONETWOONE) then
  704. call one_two_one(field, &
  705. start_patch_i, end_patch_i, &
  706. start_patch_j, end_patch_j, &
  707. sm1, em1, &
  708. sm2, em2, &
  709. min_level, max_level, &
  710. smth_passes, msg_fill_val)
  711. else if (smth_opt == SMTHDESMTH) then
  712. call smth_desmth(field, &
  713. start_patch_i, end_patch_i, &
  714. start_patch_j, end_patch_j, &
  715. sm1, em1, &
  716. sm2, em2, &
  717. min_level, max_level, &
  718. smth_passes, msg_fill_val)
  719. else if (smth_opt == SMTHDESMTH_SPECIAL) then
  720. call smth_desmth_special(field, &
  721. start_patch_i, end_patch_i, &
  722. start_patch_j, end_patch_j, &
  723. sm1, em1, &
  724. sm2, em2, &
  725. min_level, max_level, &
  726. smth_passes, msg_fill_val)
  727. end if
  728. else if (grid_type == 'E') then
  729. if (trim(fieldname) == 'HGT_M' ) then
  730. topo_flag_val=1.0
  731. mass_flag=1.0
  732. else if (trim(fieldname) == 'HGT_V') then
  733. topo_flag_val=1.0
  734. mass_flag=0.0
  735. else
  736. topo_flag_val=0.0
  737. end if
  738. if (smth_opt == ONETWOONE) then
  739. call one_two_one_egrid(field, &
  740. start_patch_i, end_patch_i, &
  741. start_patch_j, end_patch_j, &
  742. sm1, em1, &
  743. sm2, em2, &
  744. min_level, max_level, &
  745. smth_passes, topo_flag_val, mass_flag)
  746. else if (smth_opt == SMTHDESMTH) then
  747. call smth_desmth_egrid(field, &
  748. start_patch_i, end_patch_i, &
  749. start_patch_j, end_patch_j, &
  750. sm1, em1, &
  751. sm2, em2, &
  752. min_level, max_level, &
  753. smth_passes, topo_flag_val, mass_flag)
  754. else if (smth_opt == SMTHDESMTH_SPECIAL) then
  755. call mprintf(.true.,WARN,'smth-desmth_special is not currently implemented for NMM. '// &
  756. 'No smoothing will be done.')
  757. end if
  758. end if
  759. end if
  760. call write_field(sm1, em1, sm2, em2, &
  761. min_level, max_level, trim(fieldname), datestr, real_array=field)
  762. ! Do we calculate directional derivatives from this field?
  763. call get_dfdx_name(fieldname, gradname, istatus)
  764. if (istatus == 0) then
  765. allocate(slp_field(sm1:em1,sm2:em2,min_level:max_level))
  766. field_count = field_count + 1
  767. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  768. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=gradname)
  769. if (grid_type == 'C') then
  770. call calc_dfdx(field, slp_field, sm1, sm2, min_level, em1, em2, max_level, &
  771. which_domain, mapfac_ptr_x, subgrid_var)
  772. else if (grid_type == 'E') then
  773. call calc_dfdx(field, slp_field, sm1, sm2, min_level, em1, em2, max_level, &
  774. which_domain, subgrid_var=subgrid_var)
  775. end if
  776. call write_field(sm1, em1, sm2, em2, &
  777. min_level, max_level, trim(gradname), datestr, real_array=slp_field)
  778. deallocate(slp_field)
  779. end if
  780. call get_dfdy_name(fieldname, gradname, istatus)
  781. if (istatus == 0) then
  782. allocate(slp_field(sm1:em1,sm2:em2,min_level:max_level))
  783. field_count = field_count + 1
  784. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  785. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=gradname)
  786. if (grid_type == 'C') then
  787. call calc_dfdy(field, slp_field, sm1, sm2, min_level, em1, em2, max_level, &
  788. which_domain, mapfac_ptr_y, subgrid_var)
  789. else if (grid_type == 'E') then
  790. call calc_dfdy(field, slp_field, sm1, sm2, min_level, em1, em2, max_level, &
  791. which_domain, subgrid_var=subgrid_var)
  792. end if
  793. call write_field(sm1, em1, sm2, em2, &
  794. min_level, max_level, trim(gradname), datestr, real_array=slp_field)
  795. deallocate(slp_field)
  796. end if
  797. deallocate(field)
  798. ! Destination field type is CATEGORICAL
  799. else
  800. call get_max_categories(fieldname, min_category, max_category, istatus)
  801. allocate(field(sm1:em1, sm2:em2, min_category:max_category))
  802. ! Do we calculate a dominant category for this field?
  803. call get_domcategory_name(fieldname, domname, only_save_dominant, idomcatstatus)
  804. if (.not. only_save_dominant) then
  805. field_count = field_count + 1
  806. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  807. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=fieldname)
  808. else
  809. field_count = field_count + 1
  810. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  811. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=domname)
  812. end if
  813. if ( subgrid_var ) then
  814. call calc_field(fieldname, field, xlat_ptr, xlon_ptr, istagger, &
  815. sm1, em1, sm2, em2, min_category, max_category, &
  816. processed_domain, 1, sr_x=sr_x, sr_y=sr_y)
  817. else
  818. call calc_field(fieldname, field, xlat_ptr, xlon_ptr, istagger, &
  819. sm1, em1, sm2, em2, min_category, max_category, &
  820. processed_domain, 1, landmask=landmask)
  821. end if
  822. ! Find fractions
  823. do i=sm1, em1
  824. do j=sm2, em2
  825. sum = 0.
  826. do k=min_category,max_category
  827. sum = sum + field(i,j,k)
  828. end do
  829. if (sum > 0.0) then
  830. do k=min_category,max_category
  831. field(i,j,k) = field(i,j,k) / sum
  832. end do
  833. else
  834. do k=min_category,max_category
  835. field(i,j,k) = msg_fill_val
  836. end do
  837. end if
  838. end do
  839. end do
  840. ! If user wants to halt when a missing value is found in output field, check now
  841. if (halt_on_missing) then
  842. do i=sm1, em1
  843. do j=sm2, em2
  844. ! Only need to examine k=1
  845. if (field(i,j,1) == msg_fill_val) then
  846. call mprintf(.true.,ERROR,' Missing value encountered in output field. Quitting.')
  847. end if
  848. end do
  849. end do
  850. end if
  851. ! If we should only save the dominant category, then no need to write out fractional field
  852. if (.not.only_save_dominant .or. (idomcatstatus /= 0)) then
  853. ! Finally, we may be asked to smooth the fractional field
  854. call get_smooth_option(fieldname, smth_opt, smth_passes, istatus)
  855. if (istatus == 0) then
  856. if (grid_type == 'C') then
  857. if (smth_opt == ONETWOONE) then
  858. call one_two_one(field, &
  859. start_patch_i, end_patch_i, &
  860. start_patch_j, end_patch_j, &
  861. sm1, em1, &
  862. sm2, em2, &
  863. min_category, max_category, &
  864. smth_passes, msg_fill_val)
  865. else if (smth_opt == SMTHDESMTH) then
  866. call smth_desmth(field, &
  867. start_patch_i, end_patch_i, &
  868. start_patch_j, end_patch_j, &
  869. sm1, em1, &
  870. sm2, em2, &
  871. min_category, max_category, &
  872. smth_passes, msg_fill_val)
  873. else if (smth_opt == SMTHDESMTH_SPECIAL) then
  874. call smth_desmth_special(field, &
  875. start_patch_i, end_patch_i, &
  876. start_patch_j, end_patch_j, &
  877. sm1, em1, &
  878. sm2, em2, &
  879. min_category, max_category, &
  880. smth_passes, msg_fill_val)
  881. end if
  882. else if (grid_type == 'E') then
  883. if (smth_opt == ONETWOONE) then
  884. call one_two_one_egrid(field, &
  885. start_patch_i, end_patch_i, &
  886. start_patch_j, end_patch_j, &
  887. sm1, em1, &
  888. sm2, em2, &
  889. min_category, max_category, &
  890. smth_passes, msg_fill_val, 1.0)
  891. else if (smth_opt == SMTHDESMTH) then
  892. call smth_desmth_egrid(field, &
  893. start_patch_i, end_patch_i, &
  894. start_patch_j, end_patch_j, &
  895. sm1, em1, &
  896. sm2, em2, &
  897. min_category, max_category, &
  898. smth_passes, msg_fill_val, 1.0)
  899. else if (smth_opt == SMTHDESMTH_SPECIAL) then
  900. call mprintf(.true.,WARN,'smth-desmth_special is not currently implemented for NMM. '// &
  901. 'No smoothing will be done.')
  902. end if
  903. end if
  904. end if
  905. call write_field(sm1, em1, sm2, em2, &
  906. min_category, max_category, trim(fieldname), datestr, real_array=field)
  907. end if
  908. if (idomcatstatus == 0) then
  909. call mprintf(.true.,STDOUT,' Processing %s', s1=trim(domname))
  910. allocate(dominant_field(sm1:em1, sm2:em2))
  911. if (.not. only_save_dominant) then
  912. field_count = field_count + 1
  913. call mprintf(.true.,LOGFILE,'Processing field %i of %i (%s)', &
  914. i1=field_count,i2=NUM_FIELDS-NUM_AUTOMATIC_FIELDS,s1=domname)
  915. end if
  916. do i=sm1, em1
  917. do j=sm2, em2
  918. dominant = 0.
  919. dominant_field(i,j) = real(min_category-1)
  920. do k=min_category,max_category
  921. if (field(i,j,k) > dominant .and. field(i,j,k) /= msg_fill_val) then
  922. dominant_field(i,j) = real(k)
  923. dominant = field(i,j,k)
  924. ! else
  925. ! dominant_field(i,j) = nint(msg_fill_val)
  926. ! Maybe we should put an else clause here to set the category equal to the missing fill value?
  927. ! BUG: The problem here seems to be that, when we set a fraction equal to the missing fill value
  928. ! above, if the last fractional index we process here has been filled, we think that the dominant
  929. ! category should be set to the missing fill value. Perhaps we could do some check to only
  930. ! assign the msg_fill_val if no other valid category has been assigned? But this may still not
  931. ! work if the missing fill value is something like 0.5. Somehow use bitarrays, perhaps, to remember
  932. ! which points are missing and which just happen to have the missing fill value?
  933. end if
  934. end do
  935. if (dominant_field(i,j) == real(min_category-1)) dominant_field(i,j) = msg_fill_val
  936. end do
  937. end do
  938. call write_field(sm1, em1, sm2, em2, 1, 1, &
  939. trim(domname), datestr, dominant_field)
  940. deallocate(dominant_field)
  941. end if
  942. deallocate(field)
  943. end if
  944. end if
  945. end if
  946. end do
  947. ! Close output
  948. call output_close()
  949. call hash_destroy(processed_fieldnames)
  950. ! Free up memory
  951. if (associated(xlat_array)) deallocate(xlat_array)
  952. if (associated(xlon_array)) deallocate(xlon_array)
  953. if (grid_type == 'C') then
  954. if (associated(xlat_array_u)) deallocate(xlat_array_u)
  955. if (associated(xlon_array_u)) deallocate(xlon_array_u)
  956. if (associated(mapfac_array_u_x)) deallocate(mapfac_array_u_x)
  957. if (associated(mapfac_array_u_y)) deallocate(mapfac_array_u_y)
  958. end if
  959. if (associated(xlat_array_v)) deallocate(xlat_array_v)
  960. if (associated(xlon_array_v)) deallocate(xlon_array_v)
  961. if (associated(mapfac_array_m_x)) deallocate(mapfac_array_m_x)
  962. if (associated(mapfac_array_m_y)) deallocate(mapfac_array_m_y)
  963. if (associated(mapfac_array_v_x)) deallocate(mapfac_array_v_x)
  964. if (associated(mapfac_array_v_y)) deallocate(mapfac_array_v_y)
  965. if (associated(landmask)) deallocate(landmask)
  966. if (associated(xlat_array_subgrid)) deallocate(xlat_array_subgrid)
  967. if (associated(xlon_array_subgrid)) deallocate(xlon_array_subgrid)
  968. if (associated(mapfac_array_x_subgrid)) deallocate(mapfac_array_x_subgrid)
  969. if (associated(mapfac_array_y_subgrid)) deallocate(mapfac_array_y_subgrid)
  970. nullify(xlat_ptr)
  971. nullify(xlon_ptr)
  972. end subroutine process_tile
  973. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  974. ! Name: calc_field
  975. !
  976. ! Purpose: This routine fills in the "field" array with interpolated source
  977. ! data. When multiple resolutions of source data are available, an appropriate
  978. ! resolution is chosen automatically. The specified field may either be a
  979. ! continuous field or a categorical field.
  980. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  981. recursive subroutine calc_field(fieldname, field, xlat_array, xlon_array, istagger, &
  982. start_i, end_i, start_j, end_j, start_k, end_k, &
  983. processed_domain, ilevel, landmask, sr_x, sr_y)
  984. use bitarray_module
  985. use interp_module
  986. use llxy_module
  987. use misc_definitions_module
  988. use proc_point_module
  989. use queue_module
  990. use source_data_module
  991. implicit none
  992. ! Arguments
  993. integer, intent(in) :: start_i, end_i, start_j, end_j, start_k, end_k, ilevel, istagger
  994. real, dimension(start_i:end_i, start_j:end_j), intent(in) :: xlat_array, xlon_array
  995. real, dimension(start_i:end_i, start_j:end_j, start_k:end_k), intent(inout) :: field
  996. real, dimension(start_i:end_i, start_j:end_j), intent(in), optional :: landmask
  997. integer, intent(in), optional :: sr_x, sr_y
  998. character (len=128), intent(in) :: fieldname
  999. type (bitarray), intent(inout) :: processed_domain
  1000. ! Local variables
  1001. integer :: start_src_k, end_src_k
  1002. integer :: i, j, k, ix, iy, itype
  1003. integer :: user_iproj, istatus
  1004. real :: mask_val
  1005. real :: temp
  1006. real :: scale_factor
  1007. real :: msg_val, msg_fill_val, threshold, src_dx, src_dy, dom_dx, dom_dy
  1008. real :: user_stand_lon, user_truelat1, user_truelat2, user_dxkm, user_dykm, &
  1009. user_known_x, user_known_y, user_known_lat, user_known_lon
  1010. real, pointer, dimension(:,:,:) :: data_count
  1011. integer, pointer, dimension(:) :: interp_type
  1012. character (len=128) :: interp_string
  1013. type (bitarray) :: bit_domain, level_domain
  1014. type (queue) :: point_queue, tile_queue
  1015. type (q_data) :: current_pt
  1016. ! If this is the first trip through this routine, we need to allocate the bit array that
  1017. ! will persist through all recursive calls, tracking which grid points have been assigned
  1018. ! a value.
  1019. if (ilevel == 1) call bitarray_create(processed_domain, end_i-start_i+1, end_j-start_j+1)
  1020. ! Find out the projection of the data for this "priority level" (given by ilevel)
  1021. call get_data_projection(fieldname, user_iproj, user_stand_lon, user_truelat1, user_truelat2, &
  1022. user_dxkm, user_dykm, user_known_x, user_known_y, user_known_lat, &
  1023. user_known_lon, ilevel, istatus)
  1024. ! A bad status indicates that that no data for priority level ilevel is available, and thus, that
  1025. ! no further levels will be specified. We are done processing for this level.
  1026. if (istatus /= 0) then
  1027. if (ilevel == 1) call bitarray_destroy(processed_domain)
  1028. return
  1029. end if
  1030. ! A good status indicates that there is data for this priority level, so we store the projection
  1031. ! of that data on a stack. The projection will be on the top of the stack (and hence will be
  1032. ! the "active" projection) once all higher-priority levels have been processed
  1033. call push_source_projection(user_iproj, user_stand_lon, user_truelat1, user_truelat2, &
  1034. user_dxkm, user_dykm, user_dykm, user_dxkm, user_known_x, user_known_y, &
  1035. user_known_lat, user_known_lon)
  1036. ! Before proceeding with processing for this level, though, process for the next highest priority level
  1037. ! of source data
  1038. call calc_field(fieldname, field, xlat_array, xlon_array, istagger, start_i, end_i, &
  1039. start_j, end_j, start_k, end_k, processed_domain, ilevel+1, landmask, sr_x, sr_y)
  1040. ! At this point, all levels of source data with higher priority have been processed, and we can assign
  1041. ! values to all grid points that have not already been given values from higher-priority data
  1042. ! Initialize point processing module
  1043. call proc_point_init()
  1044. ! Initialize queues
  1045. call q_init(point_queue)
  1046. call q_init(tile_queue)
  1047. ! Determine whether we will be processing categorical data or continuous data
  1048. itype = iget_source_fieldtype(fieldname, ilevel, istatus)
  1049. call get_interp_option(fieldname, ilevel, interp_string, istatus)
  1050. interp_type => interp_array_from_string(interp_string)
  1051. ! Also, check whether we will be using the cell averaging interpolator for continuous fields
  1052. if (index(interp_string,'average_gcell') /= 0 .and. itype == CONTINUOUS) then
  1053. call get_gcell_threshold(interp_string, threshold, istatus)
  1054. if (istatus == 0) then
  1055. call get_source_resolution(fieldname, ilevel, src_dx, src_dy, istatus)
  1056. if (istatus == 0) then
  1057. call get_domain_resolution(dom_dx, dom_dy)
  1058. if (gridtype == 'C') then
  1059. if (threshold*max(src_dx,src_dy)*111. <= max(dom_dx,dom_dy)/1000.) then
  1060. itype = SP_CONTINUOUS
  1061. allocate(data_count(start_i:end_i,start_j:end_j,start_k:end_k))
  1062. data_count = 0.
  1063. end if
  1064. else if (gridtype == 'E') then
  1065. if (max(src_dx,src_dy) >= threshold*max(dom_dx,dom_dy)) then
  1066. itype = SP_CONTINUOUS
  1067. allocate(data_count(start_i:end_i,start_j:end_j,start_k:end_k))
  1068. data_count = 0.
  1069. end if
  1070. end if
  1071. end if
  1072. end if
  1073. end if
  1074. call get_missing_value(fieldname, ilevel, msg_val, istatus)
  1075. if (istatus /= 0) msg_val = NAN
  1076. call get_missing_fill_value(fieldname, msg_fill_val, istatus)
  1077. if (istatus /= 0) msg_fill_val = NAN
  1078. call get_masked_value(fieldname, ilevel, mask_val, istatus)
  1079. if (istatus /= 0) mask_val = -1.
  1080. if (itype == CONTINUOUS .or. itype == SP_CONTINUOUS) then
  1081. call get_source_levels(fieldname, ilevel, start_src_k, end_src_k, istatus)
  1082. if (istatus /= 0) return
  1083. end if
  1084. ! Initialize bitarray used to track which points have been visited and assigned values while
  1085. ! processing *this* priority level of data
  1086. call bitarray_create(bit_domain, end_i-start_i+1, end_j-start_j+1)
  1087. call bitarray_create(level_domain, end_i-start_i+1, end_j-start_j+1)
  1088. ! Begin by placing a point in the tile_queue
  1089. current_pt%lat = xlat_array(start_i,start_j)
  1090. current_pt%lon = xlon_array(start_i,start_j)
  1091. current_pt%x = start_i
  1092. current_pt%y = start_j
  1093. call q_insert(tile_queue, current_pt)
  1094. ! While there are still grid points in tiles that have not yet been processed
  1095. do while (q_isdata(tile_queue))
  1096. ! Take a point from the outer queue and place it in the point_queue for processing
  1097. current_pt = q_remove(tile_queue)
  1098. ! If this level of data is categorical (i.e., is given as an array of category indices),
  1099. ! then first try to process the entire tile in one call to accum_categorical. Any grid
  1100. ! points that are not given values by accum_categorical and that lie within the current
  1101. ! tile of source data are individually assigned values in the inner loop
  1102. if (itype == CATEGORICAL) then
  1103. ! Have we already visited this point? If so, this tile has already been processed by
  1104. ! accum_categorical.
  1105. if (.not. bitarray_test(bit_domain, current_pt%x-start_i+1, current_pt%y-start_j+1)) then
  1106. call q_insert(point_queue, current_pt)
  1107. if (.not. have_processed_tile(current_pt%lat, current_pt%lon, fieldname, ilevel)) then
  1108. call accum_categorical(current_pt%lat, current_pt%lon, istagger, field, &
  1109. start_i, end_i, start_j, end_j, start_k, end_k, &
  1110. fieldname, processed_domain, level_domain, &
  1111. ilevel, msg_val, mask_val, sr_x, sr_y)
  1112. ! BUG: Where do we mask out those points that are on land/water when masked=land/water is set?
  1113. end if
  1114. call bitarray_set(bit_domain, current_pt%x-start_i+1, current_pt%y-start_j+1)
  1115. end if
  1116. else if (itype == SP_CONTINUOUS) then
  1117. ! Have we already visited this point? If so, this tile has already been processed by
  1118. ! accum_continuous.
  1119. if (.not. bitarray_test(bit_domain, current_pt%x-start_i+1, current_pt%y-start_j+1)) then
  1120. call q_insert(point_queue, current_pt)
  1121. if (.not. have_processed_tile(current_pt%lat, current_pt%lon, fieldname, ilevel)) then
  1122. call accum_continuous(current_pt%lat, current_pt%lon, istagger, field, data_count, &
  1123. start_i, end_i, start_j, end_j, start_k, end_k, &
  1124. fieldname, processed_domain, level_domain, &
  1125. ilevel, msg_val, mask_val, sr_x, sr_y)
  1126. ! BUG: Where do we mask out those points that are on land/water when masked=land/water is set?
  1127. end if
  1128. call bitarray_set(bit_domain, current_pt%x-start_i+1, current_pt%y-start_j+1)
  1129. end if
  1130. else if (itype == CONTINUOUS) then
  1131. ! Have we already visited this point? If so, the tile containing this point has already been
  1132. ! processed in the inner loop.
  1133. if (.not. bitarray_test(bit_domain, current_pt%x-start_i+1, current_pt%y-start_j+1)) then
  1134. call q_insert(point_queue, current_pt)
  1135. call bitarray_set(bit_domain, current_pt%x-start_i+1, current_pt%y-start_j+1)
  1136. end if
  1137. end if
  1138. ! This inner loop, where all grid points contained in the current source tile are processed
  1139. do while (q_isdata(point_queue))
  1140. current_pt = q_remove(point_queue)
  1141. ix = current_pt%x
  1142. iy = current_pt%y
  1143. ! Process the current point
  1144. if (itype == CONTINUOUS .or. itype == SP_CONTINUOUS) then
  1145. ! Have we already assigned this point a value from this priority level?
  1146. if (.not. bitarray_test(level_domain, ix-start_i+1, iy-start_j+1)) then
  1147. ! If the point was already assigned a value from a higher-priority level, no
  1148. ! need to assign a new value
  1149. if (bitarray_test(processed_domain, ix-start_i+1, iy-start_j+1)) then
  1150. call bitarray_set(level_domain, ix-start_i+1, iy-start_j+1)
  1151. ! Otherwise, need to assign values from this level of source data if we can
  1152. else
  1153. if (present(landmask) .and. (istagger == M .or. istagger == HH)) then
  1154. if (landmask(ix,iy) /= mask_val) then
  1155. do k=start_src_k,end_src_k
  1156. temp = get_point(current_pt%lat, current_pt%lon, k, &
  1157. fieldname, ilevel, interp_type, msg_val)
  1158. if (temp /= msg_val) then
  1159. field(ix, iy, k) = temp
  1160. call bitarray_set(level_domain, ix-start_i+1, iy-start_j+1)
  1161. if (itype == SP_CONTINUOUS) data_count(ix, iy, k) = 1.0
  1162. else
  1163. field(ix, iy, k) = msg_fill_val
  1164. end if
  1165. end do
  1166. else
  1167. do k=start_k,end_k
  1168. field(ix,iy,k) = msg_fill_val
  1169. end do
  1170. end if
  1171. else
  1172. do k=start_src_k,end_src_k
  1173. temp = get_point(current_pt%lat, current_pt%lon, k, &
  1174. fieldname, ilevel, interp_type, msg_val)
  1175. if (temp /= msg_val) then
  1176. field(ix, iy, k) = temp
  1177. call bitarray_set(level_domain, ix-start_i+1, iy-start_j+1)
  1178. if (itype == SP_CONTINUOUS) data_count(ix, iy, k) = 1.0
  1179. else
  1180. field(ix, iy, k) = msg_fill_val
  1181. end if
  1182. end do
  1183. end if
  1184. end if
  1185. end if
  1186. else if (itype == CATEGORICAL) then
  1187. ! Have we already assigned this point a value from this priority level?
  1188. if (.not.bitarray_test(level_domain, ix-start_i+1, iy-start_j+1)) then
  1189. ! If the point was already assigned a value from a higher-priority level, no
  1190. ! need to assign a new value
  1191. if (bitarray_test(processed_domain, ix-start_i+1, iy-start_j+1)) then
  1192. call bitarray_set(level_domain, ix-start_i+1, iy-start_j+1)
  1193. ! Otherwise, the point was apparently not given a value when accum_categorical
  1194. ! was called for the current tile, and we need to assign values from this
  1195. ! level of source data if we can
  1196. else
  1197. if (present(landmask) .and. (istagger == M .or. istagger == HH)) then
  1198. if (landmask(ix,iy) /= mask_val) then
  1199. temp = get_point(current_pt%lat, current_pt%lon, 1, &
  1200. fieldname, ilevel, interp_type, msg_val)
  1201. do k=start_k,end_k
  1202. field(ix,iy,k) = 0.
  1203. end do
  1204. if (temp /= msg_val) then
  1205. if (int(temp) >= start_k .and. int(temp) <= end_k) then
  1206. field(ix, iy, int(temp)) = field(ix, iy, int(temp)) + 1.
  1207. else
  1208. call mprintf(.true.,WARN,' Attempted to assign an invalid category '// &
  1209. '%i to grid point (%i, %i)', i1=int(temp), i2=ix, i3=iy)
  1210. end if
  1211. call bitarray_set(level_domain, ix-start_i+1, iy-start_j+1)
  1212. end if
  1213. else
  1214. do k=start_k,end_k
  1215. field(ix,iy,k) = 0.
  1216. end do
  1217. end if
  1218. else
  1219. temp = get_point(current_pt%lat, current_pt%lon, 1, &
  1220. fieldname, ilevel, interp_type, msg_val)
  1221. do k=start_k,end_k
  1222. field(ix,iy,k) = 0.
  1223. end do
  1224. if (temp /= msg_val) then
  1225. if (int(temp) >= start_k .and. int(temp) <= end_k) then
  1226. field(ix, iy, int(temp)) = field(ix, iy, int(temp)) + 1.
  1227. else
  1228. call mprintf(.true.,WARN,' Attempted to assign an invalid category '// &
  1229. '%i to grid point (%i, %i)', i1=int(temp), i2=ix, i3=iy)
  1230. end if
  1231. call bitarray_set(level_domain, ix-start_i+1, iy-start_j+1)
  1232. end if
  1233. end if
  1234. end if
  1235. end if
  1236. end if
  1237. ! Scan neighboring points, adding them to the appropriate queue based on whether they
  1238. ! are in the current tile or not
  1239. if (iy > start_j) then
  1240. if (ix > start_i) then
  1241. ! Neighbor with relative position (-1,-1)
  1242. call process_neighbor(ix-1, iy-1, bit_domain, point_queue, tile_queue, &
  1243. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1244. end if
  1245. ! Neighbor with relative position (0,-1)
  1246. call process_neighbor(ix, iy-1, bit_domain, point_queue, tile_queue, &
  1247. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1248. if (ix < end_i) then
  1249. ! Neighbor with relative position (+1,-1)
  1250. call process_neighbor(ix+1, iy-1, bit_domain, point_queue, tile_queue, &
  1251. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1252. end if
  1253. end if
  1254. if (ix > start_i) then
  1255. ! Neighbor with relative position (-1,0)
  1256. call process_neighbor(ix-1, iy, bit_domain, point_queue, tile_queue, &
  1257. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1258. end if
  1259. if (ix < end_i) then
  1260. ! Neighbor with relative position (+1,0)
  1261. call process_neighbor(ix+1, iy, bit_domain, point_queue, tile_queue, &
  1262. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1263. end if
  1264. if (iy < end_j) then
  1265. if (ix > start_i) then
  1266. ! Neighbor with relative position (-1,+1)
  1267. call process_neighbor(ix-1, iy+1, bit_domain, point_queue, tile_queue, &
  1268. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1269. end if
  1270. ! Neighbor with relative position (0,+1)
  1271. call process_neighbor(ix, iy+1, bit_domain, point_queue, tile_queue, &
  1272. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1273. if (ix < end_i) then
  1274. ! Neighbor with relative position (+1,+1)
  1275. call process_neighbor(ix+1, iy+1, bit_domain, point_queue, tile_queue, &
  1276. xlat_array, xlon_array, start_i, end_i, start_j, end_j, ilevel)
  1277. end if
  1278. end if
  1279. end do
  1280. end do
  1281. if (itype == SP_CONTINUOUS) then
  1282. itype = CONTINUOUS
  1283. if (present(landmask) .and. (istagger == M .or. istagger == HH)) then
  1284. do j=start_j,end_j
  1285. do i=start_i,end_i
  1286. if (landmask(i,j) /= mask_val) then
  1287. do k=start_k,end_k
  1288. if (data_count(i,j,k) > 0.) then
  1289. field(i,j,k) = field(i,j,k) / data_count(i,j,k)
  1290. else
  1291. if (.not.bitarray_test(processed_domain, i-start_i+1, j-start_j+1)) then
  1292. field(i,j,k) = msg_fill_val
  1293. end if
  1294. end if
  1295. end do
  1296. else
  1297. if (.not.bitarray_test(processed_domain, i-start_i+1, j-start_j+1)) then
  1298. do k=start_k,end_k
  1299. field(i,j,k) = msg_fill_val
  1300. end do
  1301. end if
  1302. end if
  1303. end do
  1304. end do
  1305. else
  1306. do k=start_k,end_k
  1307. do j=start_j,end_j
  1308. do i=start_i,end_i
  1309. if (data_count(i,j,k) > 0.) then
  1310. field(i,j,k) = field(i,j,k) / data_count(i,j,k)
  1311. else
  1312. if (.not.bitarray_test(processed_domain, i-start_i+1, j-start_j+1)) then
  1313. field(i,j,k) = msg_fill_val
  1314. end if
  1315. end if
  1316. end do
  1317. end do
  1318. end do
  1319. end if
  1320. deallocate(data_count)
  1321. else if (itype == CATEGORICAL) then
  1322. if (present(landmask) .and. (istagger == M .or. istagger == HH)) then
  1323. do j=start_j,end_j
  1324. do i=start_i,end_i
  1325. if (landmask(i,j) == mask_val) then
  1326. do k=start_k,end_k
  1327. field(i,j,k) = 0.
  1328. end do
  1329. end if
  1330. end do
  1331. end do
  1332. end if
  1333. end if
  1334. deallocate(interp_type)
  1335. ! We may need to scale this field by a constant
  1336. call get_field_scale_factor(fieldname, ilevel, scale_factor, istatus)
  1337. if (istatus == 0) then
  1338. do i=start_i, end_i
  1339. do j=start_j, end_j
  1340. if (bitarray_test(level_domain,i-start_i+1,j-start_j+1) .and. &
  1341. .not. bitarray_test(processed_domain,i-start_i+1,j-start_j+1)) then
  1342. do k=start_k,end_k
  1343. if (field(i,j,k) /= msg_fill_val) then
  1344. field(i,j,k) = field(i,j,k) * scale_factor
  1345. end if
  1346. end do
  1347. end if
  1348. end do
  1349. end do
  1350. end if
  1351. ! Now add the points that were assigned values at this priority level to the complete array
  1352. ! of points that have been assigned values
  1353. call bitarray_merge(processed_domain, level_domain)
  1354. call bitarray_destroy(bit_domain)
  1355. call bitarray_destroy(level_domain)
  1356. call q_destroy(point_queue)
  1357. call q_destroy(tile_queue)
  1358. call proc_point_shutdown()
  1359. ! If this is the last level of the recursion, we can also deallocate processed_domain
  1360. if (ilevel == 1) call bitarray_destroy(processed_domain)
  1361. ! Remove the projection of the current level of source data from the stack, thus "activating"
  1362. ! the projection of the next highest level
  1363. call pop_source_projection()
  1364. end subroutine calc_field
  1365. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1366. ! Name: get_lat_lon_fields
  1367. !
  1368. ! Purpose: To calculate the latitude and longitude for every gridpoint in the
  1369. ! tile of the model domain. The caller may specify that the grid for which
  1370. ! values are computed is staggered or unstaggered using the "stagger"
  1371. ! argument.
  1372. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1373. subroutine get_lat_lon_fields(xlat_arr, xlon_arr, start_mem_i, &
  1374. start_mem_j, end_mem_i, end_mem_j, stagger, comp_ll, &
  1375. sub_x, sub_y)
  1376. use llxy_module
  1377. use misc_definitions_module
  1378. implicit none
  1379. ! Arguments
  1380. integer, intent(in) :: start_mem_i, start_mem_j, end_mem_i, &
  1381. end_mem_j, stagger
  1382. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(out) :: xlat_arr, xlon_arr
  1383. logical, optional, intent(in) :: comp_ll
  1384. integer, optional, intent(in) :: sub_x, sub_y
  1385. ! Local variables
  1386. integer :: i, j
  1387. real :: rx, ry, dx, dy
  1388. rx = 1.0
  1389. ry = 1.0
  1390. dx = 1.0
  1391. dy = 1.0
  1392. if (present(sub_x)) then
  1393. rx = real(sub_x)
  1394. dx = .5 + .5/rx
  1395. end if
  1396. if (present(sub_y)) then
  1397. ry = real(sub_y)
  1398. dy = .5 + .5/ry
  1399. end if
  1400. do i=start_mem_i, end_mem_i
  1401. do j=start_mem_j, end_mem_j
  1402. call xytoll(real(i-1)/rx+dx, real(j-1)/ry+dy, &
  1403. xlat_arr(i,j), xlon_arr(i,j), stagger, comp_ll=comp_ll)
  1404. end do
  1405. end do
  1406. end subroutine get_lat_lon_fields
  1407. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1408. ! Name: get_map_factor
  1409. !
  1410. ! Purpose: Given the latitude field, this routine calculates map factors for
  1411. ! the grid points of the specified domain. For different grids (e.g., C grid,
  1412. ! E grid), the latitude array should provide the latitudes of the points for
  1413. ! which map factors are to be calculated.
  1414. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1415. subroutine get_map_factor(xlat_arr, xlon_arr, mapfac_arr_x, mapfac_arr_y, &
  1416. start_mem_i, start_mem_j, end_mem_i, end_mem_j)
  1417. use constants_module
  1418. use gridinfo_module
  1419. use misc_definitions_module
  1420. use map_utils
  1421. implicit none
  1422. ! Arguments
  1423. integer, intent(in) :: start_mem_i, start_mem_j, end_mem_i, end_mem_j
  1424. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(in) :: xlat_arr, xlon_arr
  1425. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(out) :: mapfac_arr_x
  1426. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(out) :: mapfac_arr_y
  1427. ! Local variables
  1428. integer :: i, j
  1429. real :: n, colat, colat0, colat1, colat2, comp_lat, comp_lon
  1430. !
  1431. ! Equations for map factor given in Principles of Meteorological Analysis,
  1432. ! Walter J. Saucier, pp. 32-33
  1433. !
  1434. ! Lambert conformal projection
  1435. if (iproj_type == PROJ_LC) then
  1436. if (truelat1 /= truelat2) then
  1437. colat1 = rad_per_deg*(90.0 - truelat1)
  1438. colat2 = rad_per_deg*(90.0 - truelat2)
  1439. n = (log(sin(colat1)) - log(sin(colat2))) &
  1440. / (log(tan(colat1/2.0)) - log(tan(colat2/2.0)))
  1441. do i=start_mem_i, end_mem_i
  1442. do j=start_mem_j, end_mem_j
  1443. colat = rad_per_deg*(90.0 - xlat_arr(i,j))
  1444. mapfac_arr_x(i,j) = sin(colat2)/sin(colat)*(tan(colat/2.0)/tan(colat2/2.0))**n
  1445. mapfac_arr_y(i,j) = mapfac_arr_x(i,j)
  1446. end do
  1447. end do
  1448. else
  1449. colat0 = rad_per_deg*(90.0 - truelat1)
  1450. do i=start_mem_i, end_mem_i
  1451. do j=start_mem_j, end_mem_j
  1452. colat = rad_per_deg*(90.0 - xlat_arr(i,j))
  1453. mapfac_arr_x(i,j) = sin(colat0)/sin(colat)*(tan(colat/2.0)/tan(colat0/2.0))**cos(colat0)
  1454. mapfac_arr_y(i,j) = mapfac_arr_x(i,j)
  1455. end do
  1456. end do
  1457. end if
  1458. ! Polar stereographic projection
  1459. else if (iproj_type == PROJ_PS) then
  1460. do i=start_mem_i, end_mem_i
  1461. do j=start_mem_j, end_mem_j
  1462. mapfac_arr_x(i,j) = (1.0 + sin(rad_per_deg*abs(truelat1)))/(1.0 + sin(rad_per_deg*sign(1.,truelat1)*xlat_arr(i,j)))
  1463. mapfac_arr_y(i,j) = mapfac_arr_x(i,j)
  1464. end do
  1465. end do
  1466. ! Mercator projection
  1467. else if (iproj_type == PROJ_MERC) then
  1468. colat0 = rad_per_deg*(90.0 - truelat1)
  1469. do i=start_mem_i, end_mem_i
  1470. do j=start_mem_j, end_mem_j
  1471. colat = rad_per_deg*(90.0 - xlat_arr(i,j))
  1472. mapfac_arr_x(i,j) = sin(colat0) / sin(colat)
  1473. mapfac_arr_y(i,j) = mapfac_arr_x(i,j)
  1474. end do
  1475. end do
  1476. ! Global cylindrical projection
  1477. else if (iproj_type == PROJ_CYL) then
  1478. do i=start_mem_i, end_mem_i
  1479. do j=start_mem_j, end_mem_j
  1480. if (abs(xlat_arr(i,j)) == 90.0) then
  1481. mapfac_arr_x(i,j) = 0. ! MSF actually becomes infinite at poles, but
  1482. ! the values should never be used there; by
  1483. ! setting to 0, we hope to induce a "divide
  1484. ! by zero" error if they are
  1485. else
  1486. mapfac_arr_x(i,j) = 1.0 / cos(xlat_arr(i,j)*rad_per_deg)
  1487. end if
  1488. mapfac_arr_y(i,j) = 1.0
  1489. end do
  1490. end do
  1491. ! Rotated global cylindrical projection
  1492. else if (iproj_type == PROJ_CASSINI) then
  1493. if (abs(pole_lat) == 90.) then
  1494. do i=start_mem_i, end_mem_i
  1495. do j=start_mem_j, end_mem_j
  1496. if (abs(xlat_arr(i,j)) >= 90.0) then
  1497. mapfac_arr_x(i,j) = 0. ! MSF actually becomes infinite at poles, but
  1498. ! the values should never be used there; by
  1499. ! setting to 0, we hope to induce a "divide
  1500. ! by zero" error if they are
  1501. else
  1502. mapfac_arr_x(i,j) = 1.0 / cos(xlat_arr(i,j)*rad_per_deg)
  1503. end if
  1504. mapfac_arr_y(i,j) = 1.0
  1505. end do
  1506. end do
  1507. else
  1508. do i=start_mem_i, end_mem_i
  1509. do j=start_mem_j, end_mem_j
  1510. call rotate_coords(xlat_arr(i,j),xlon_arr(i,j), &
  1511. comp_lat, comp_lon, &
  1512. pole_lat, pole_lon, stand_lon, &
  1513. -1)
  1514. if (abs(comp_lat) >= 90.0) then
  1515. mapfac_arr_x(i,j) = 0. ! MSF actually becomes infinite at poles, but
  1516. ! the values should never be used there; by
  1517. ! setting to 0, we hope to induce a "divide
  1518. ! by zero" error if they are
  1519. else
  1520. mapfac_arr_x(i,j) = 1.0 / cos(comp_lat*rad_per_deg)
  1521. end if
  1522. mapfac_arr_y(i,j) = 1.0
  1523. end do
  1524. end do
  1525. end if
  1526. else if (iproj_type == PROJ_ROTLL) then
  1527. do i=start_mem_i, end_mem_i
  1528. do j=start_mem_j, end_mem_j
  1529. mapfac_arr_x(i,j) = 1.0
  1530. mapfac_arr_y(i,j) = 1.0
  1531. end do
  1532. end do
  1533. end if
  1534. end subroutine get_map_factor
  1535. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1536. ! Name: get_coriolis_parameters
  1537. !
  1538. ! Purpose: To calculate the Coriolis parameters f and e for every gridpoint in
  1539. ! the tile of the model domain
  1540. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1541. subroutine get_coriolis_parameters(xlat_arr, f, e, &
  1542. start_mem_i, start_mem_j, end_mem_i, end_mem_j)
  1543. use constants_module
  1544. implicit none
  1545. ! Arguments
  1546. integer, intent(in) :: start_mem_i, start_mem_j, end_mem_i, end_mem_j
  1547. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(in) :: xlat_arr
  1548. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(out) :: f, e
  1549. ! Local variables
  1550. integer :: i, j
  1551. do i=start_mem_i, end_mem_i
  1552. do j=start_mem_j, end_mem_j
  1553. f(i,j) = 2.0*OMEGA_E*sin(rad_per_deg*xlat_arr(i,j))
  1554. e(i,j) = 2.0*OMEGA_E*cos(rad_per_deg*xlat_arr(i,j))
  1555. end do
  1556. end do
  1557. end subroutine get_coriolis_parameters
  1558. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1559. ! Name: get_rotang
  1560. !
  1561. ! Purpose: To calculate the sine and cosine of rotation angle.
  1562. !
  1563. ! NOTES: The formulas used in this routine come from those in the
  1564. ! vecrot_rotlat() routine of the original WRF SI.
  1565. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1566. subroutine get_rotang(xlat_arr, xlon_arr, cosa, sina, &
  1567. start_mem_i, start_mem_j, end_mem_i, end_mem_j)
  1568. use constants_module
  1569. use gridinfo_module
  1570. implicit none
  1571. ! Arguments
  1572. integer, intent(in) :: start_mem_i, start_mem_j, end_mem_i, end_mem_j
  1573. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(in) :: xlat_arr, xlon_arr
  1574. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(out) :: cosa, sina
  1575. ! Local variables
  1576. integer :: i, j
  1577. real :: alpha, d_lon
  1578. do i=start_mem_i, end_mem_i
  1579. do j=start_mem_j+1, end_mem_j-1
  1580. d_lon = xlon_arr(i,j+1)-xlon_arr(i,j-1)
  1581. if (d_lon > 180.) then
  1582. d_lon = d_lon - 360.
  1583. else if (d_lon < -180.) then
  1584. d_lon = d_lon + 360.
  1585. end if
  1586. alpha = atan2(-cos(xlat_arr(i,j)*RAD_PER_DEG) * (d_lon*RAD_PER_DEG), &
  1587. ((xlat_arr(i,j+1)-xlat_arr(i,j-1))*RAD_PER_DEG))
  1588. sina(i,j) = sin(alpha)
  1589. cosa(i,j) = cos(alpha)
  1590. end do
  1591. end do
  1592. do i=start_mem_i, end_mem_i
  1593. d_lon = xlon_arr(i,start_mem_j+1)-xlon_arr(i,start_mem_j)
  1594. if (d_lon > 180.) then
  1595. d_lon = d_lon - 360.
  1596. else if (d_lon < -180.) then
  1597. d_lon = d_lon + 360.
  1598. end if
  1599. alpha = atan2(-cos(xlat_arr(i,start_mem_j)*RAD_PER_DEG) * (d_lon*RAD_PER_DEG), &
  1600. ((xlat_arr(i,start_mem_j+1)-xlat_arr(i,start_mem_j))*RAD_PER_DEG))
  1601. sina(i,start_mem_j) = sin(alpha)
  1602. cosa(i,start_mem_j) = cos(alpha)
  1603. end do
  1604. do i=start_mem_i, end_mem_i
  1605. d_lon = xlon_arr(i,end_mem_j)-xlon_arr(i,end_mem_j-1)
  1606. if (d_lon > 180.) then
  1607. d_lon = d_lon - 360.
  1608. else if (d_lon < -180.) then
  1609. d_lon = d_lon + 360.
  1610. end if
  1611. alpha = atan2(-cos(xlat_arr(i,end_mem_j)*RAD_PER_DEG) * (d_lon*RAD_PER_DEG), &
  1612. ((xlat_arr(i,end_mem_j)-xlat_arr(i,end_mem_j-1))*RAD_PER_DEG))
  1613. sina(i,end_mem_j) = sin(alpha)
  1614. cosa(i,end_mem_j) = cos(alpha)
  1615. end do
  1616. end subroutine get_rotang
  1617. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1618. ! Name: process_neighbor
  1619. !
  1620. ! Purpose: This routine, give the x/y location of a point, determines whether
  1621. ! the point has already been processed, and if not, which processing queue
  1622. ! the point should be placed in.
  1623. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1624. subroutine process_neighbor(ix, iy, bit_domain, point_queue, tile_queue, &
  1625. xlat_array, xlon_array, &
  1626. start_i, end_i, start_j, end_j, ilevel)
  1627. use bitarray_module
  1628. use misc_definitions_module
  1629. use proc_point_module
  1630. use queue_module
  1631. implicit none
  1632. ! Arguments
  1633. integer, intent(in) :: ix, iy, start_i, end_i, start_j, end_j, ilevel
  1634. real, dimension(start_i:end_i, start_j:end_j), intent(in) :: xlat_array, xlon_array
  1635. type (bitarray), intent(inout) :: bit_domain
  1636. type (queue), intent(inout) :: point_queue, tile_queue
  1637. ! Local variables
  1638. type (q_data) :: process_pt
  1639. logical :: is_in_tile
  1640. ! If the point has already been visited, no need to do anything more.
  1641. if (.not. bitarray_test(bit_domain, ix-start_i+1, iy-start_j+1)) then
  1642. ! Create a queue item for the current point
  1643. process_pt%lat = xlat_array(ix,iy)
  1644. process_pt%lon = xlon_array(ix,iy)
  1645. process_pt%x = ix
  1646. process_pt%y = iy
  1647. is_in_tile = is_point_in_tile(process_pt%lat, process_pt%lon, ilevel)
  1648. ! If the point is in the current tile, add it to the list of points
  1649. ! to be processed in the inner loop
  1650. if (is_in_tile) then
  1651. call q_insert(point_queue, process_pt)
  1652. call bitarray_set(bit_domain, ix-start_i+1, iy-start_j+1)
  1653. ! Otherwise, we will process this point later. Add it to the list for
  1654. ! the outer loop.
  1655. else
  1656. call q_insert(tile_queue, process_pt)
  1657. end if
  1658. end if
  1659. end subroutine process_neighbor
  1660. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1661. ! Name: calc_dfdy
  1662. !
  1663. ! Purpose: This routine calculates df/dy for the field in src_arr, and places
  1664. ! the result in dst_array.
  1665. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1666. subroutine calc_dfdy(src_arr, dst_arr, start_mem_i, start_mem_j, start_mem_k, &
  1667. end_mem_i, end_mem_j, end_mem_k, idom, mapfac, subgrid_var)
  1668. ! Modules
  1669. use gridinfo_module
  1670. implicit none
  1671. ! Arguments
  1672. integer, intent(in) :: start_mem_i, start_mem_j, start_mem_k, end_mem_i, end_mem_j, end_mem_k
  1673. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j,start_mem_k:end_mem_k), intent(in) :: src_arr
  1674. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j,start_mem_k:end_mem_k), intent(out) :: dst_arr
  1675. integer,intent(in) :: idom
  1676. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(in), optional :: mapfac
  1677. logical, intent(in), optional :: subgrid_var
  1678. ! Local variables
  1679. integer :: i, j, k
  1680. real :: l_sr_y
  1681. ! calculate the refinement ratio from the top-level domain
  1682. l_sr_y=1.
  1683. if (present(subgrid_var)) then
  1684. if (subgrid_var) l_sr_y=subgrid_ratio_y(idom)
  1685. end if
  1686. l_sr_y=l_sr_y*moad_grid_ratio(idom)
  1687. if (present(mapfac)) then
  1688. do k=start_mem_k,end_mem_k
  1689. do i=start_mem_i, end_mem_i
  1690. do j=start_mem_j+1, end_mem_j-1
  1691. dst_arr(i,j,k) = l_sr_y*(src_arr(i,j+1,k) - src_arr(i,j-1,k))/(2.*dykm*mapfac(i,j))
  1692. end do
  1693. end do
  1694. do i=start_mem_i, end_mem_i
  1695. dst_arr(i,start_mem_j,k) = l_sr_y*(src_arr(i,start_mem_j+1,k) - src_arr(i,start_mem_j,k))/(dykm*mapfac(i,j))
  1696. end do
  1697. do i=start_mem_i, end_mem_i
  1698. dst_arr(i,end_mem_j,k) = l_sr_y*(src_arr(i,end_mem_j,k) - src_arr(i,end_mem_j-1,k))/(dykm*mapfac(i,j))
  1699. end do
  1700. end do
  1701. else
  1702. do k=start_mem_k,end_mem_k
  1703. do i=start_mem_i, end_mem_i
  1704. do j=start_mem_j+1, end_mem_j-1
  1705. dst_arr(i,j,k) = l_sr_y*(src_arr(i,j+1,k) - src_arr(i,j-1,k))/(2.*dykm)
  1706. end do
  1707. end do
  1708. do i=start_mem_i, end_mem_i
  1709. dst_arr(i,start_mem_j,k) = l_sr_y*(src_arr(i,start_mem_j+1,k) - src_arr(i,start_mem_j,k))/(dykm)
  1710. end do
  1711. do i=start_mem_i, end_mem_i
  1712. dst_arr(i,end_mem_j,k) = l_sr_y*(src_arr(i,end_mem_j,k) - src_arr(i,end_mem_j-1,k))/(dykm)
  1713. end do
  1714. end do
  1715. end if
  1716. end subroutine calc_dfdy
  1717. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1718. ! Name: calc_dfdx
  1719. !
  1720. ! Purpose: This routine calculates df/dx for the field in src_arr, and places
  1721. ! the result in dst_array.
  1722. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1723. subroutine calc_dfdx(src_arr, dst_arr, start_mem_i, start_mem_j, &
  1724. start_mem_k, end_mem_i, end_mem_j, end_mem_k, idom, mapfac, subgrid_var)
  1725. ! Modules
  1726. use gridinfo_module
  1727. implicit none
  1728. ! Arguments
  1729. integer, intent(in) :: start_mem_i, start_mem_j, start_mem_k, end_mem_i, end_mem_j, end_mem_k
  1730. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j, start_mem_k:end_mem_k), intent(in) :: src_arr
  1731. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j, start_mem_k:end_mem_k), intent(out) :: dst_arr
  1732. integer, intent(in) :: idom
  1733. real, dimension(start_mem_i:end_mem_i, start_mem_j:end_mem_j), intent(in), optional :: mapfac
  1734. logical, intent(in), optional :: subgrid_var
  1735. ! Local variables
  1736. integer :: i, j, k
  1737. real :: l_sr_x
  1738. ! calculate the refinement ratio from the top-level domain
  1739. l_sr_x=1.
  1740. if (present(subgrid_var)) then
  1741. if (subgrid_var) l_sr_x=subgrid_ratio_x(idom)
  1742. end if
  1743. l_sr_x=l_sr_x*moad_grid_ratio(idom)
  1744. if (present(mapfac)) then
  1745. do k=start_mem_k, end_mem_k
  1746. do i=start_mem_i+1, end_mem_i-1
  1747. do j=start_mem_j, end_mem_j
  1748. dst_arr(i,j,k) = l_sr_x*(src_arr(i+1,j,k) - src_arr(i-1,j,k))/(2.*dxkm*mapfac(i,j))
  1749. end do
  1750. end do
  1751. do j=start_mem_j, end_mem_j
  1752. dst_arr(start_mem_i,j,k) = l_sr_x*(src_arr(start_mem_i+1,j,k) - src_arr(start_mem_i,j,k))/(dxkm*mapfac(i,j))
  1753. end do
  1754. do j=start_mem_j, end_mem_j
  1755. dst_arr(end_mem_i,j,k) = l_sr_x*(src_arr(end_mem_i,j,k) - src_arr(end_mem_i-1,j,k))/(dxkm*mapfac(i,j))
  1756. end do
  1757. end do
  1758. else
  1759. do k=start_mem_k, end_mem_k
  1760. do i=start_mem_i+1, end_mem_i-1
  1761. do j=start_mem_j, end_mem_j
  1762. dst_arr(i,j,k) = l_sr_x*(src_arr(i+1,j,k) - src_arr(i-1,j,k))/(2.*dxkm)
  1763. end do
  1764. end do
  1765. do j=start_mem_j, end_mem_j
  1766. dst_arr(start_mem_i,j,k) = l_sr_x*(src_arr(start_mem_i+1,j,k) - src_arr(start_mem_i,j,k))/(dxkm)
  1767. end do
  1768. do j=start_mem_j, end_mem_j
  1769. dst_arr(end_mem_i,j,k) = l_sr_x*(src_arr(end_mem_i,j,k) - src_arr(end_mem_i-1,j,k))/(dxkm)
  1770. end do
  1771. end do
  1772. end if
  1773. end subroutine calc_dfdx
  1774. end module process_tile_module