remap_distwgt.f 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. !
  3. ! this module contains necessary routines for performing an
  4. ! interpolation using a distance-weighted average of n nearest
  5. ! neighbors.
  6. !
  7. !-----------------------------------------------------------------------
  8. !
  9. ! CVS:$Id: remap_distwgt.f,v 1.3 2000/04/19 21:56:26 pwjones Exp $
  10. !
  11. ! Copyright (c) 1997, 1998 the Regents of the University of
  12. ! California.
  13. !
  14. ! This software and ancillary information (herein called software)
  15. ! called SCRIP is made available under the terms described here.
  16. ! The software has been approved for release with associated
  17. ! LA-CC Number 98-45.
  18. !
  19. ! Unless otherwise indicated, this software has been authored
  20. ! by an employee or employees of the University of California,
  21. ! operator of the Los Alamos National Laboratory under Contract
  22. ! No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S.
  23. ! Government has rights to use, reproduce, and distribute this
  24. ! software. The public may copy and use this software without
  25. ! charge, provided that this Notice and any statement of authorship
  26. ! are reproduced on all copies. Neither the Government nor the
  27. ! University makes any warranty, express or implied, or assumes
  28. ! any liability or responsibility for the use of this software.
  29. !
  30. ! If software is modified to produce derivative works, such modified
  31. ! software should be clearly marked, so as not to confuse it with
  32. ! the version available from Los Alamos National Laboratory.
  33. !
  34. !***********************************************************************
  35. module remap_distance_weight
  36. !-----------------------------------------------------------------------
  37. use kinds_mod ! defines common data types
  38. use constants ! defines common constants
  39. use grids ! module containing grid info
  40. use remap_vars ! module containing remap info
  41. implicit none
  42. !-----------------------------------------------------------------------
  43. !
  44. ! module variables
  45. !
  46. !-----------------------------------------------------------------------
  47. integer (kind=int_kind), parameter ::
  48. & num_neighbors=4 ! num nearest neighbors to interpolate from
  49. real (kind=dbl_kind), dimension(:), allocatable, save ::
  50. & coslat, sinlat, ! cosine, sine of grid lats (for distance)
  51. & coslon, sinlon, ! cosine, sine of grid lons (for distance)
  52. & wgtstmp ! an array to hold the link weight
  53. !***********************************************************************
  54. contains
  55. !***********************************************************************
  56. subroutine remap_distwgt
  57. !-----------------------------------------------------------------------
  58. !
  59. ! this routine computes the inverse-distance weights for a
  60. ! nearest-neighbor interpolation.
  61. !
  62. !-----------------------------------------------------------------------
  63. !-----------------------------------------------------------------------
  64. !
  65. ! local variables
  66. !
  67. !-----------------------------------------------------------------------
  68. logical (kind=log_kind), dimension(num_neighbors) ::
  69. & nbr_mask ! mask at nearest neighbors
  70. integer (kind=int_kind) :: n,
  71. & dst_add, ! destination address
  72. & nmap ! index of current map being computed
  73. integer (kind=int_kind), dimension(num_neighbors) ::
  74. & nbr_add ! source address at nearest neighbors
  75. real (kind=dbl_kind), dimension(num_neighbors) ::
  76. & nbr_dist ! angular distance four nearest neighbors
  77. real (kind=dbl_kind) ::
  78. & coslat_dst, ! cos(lat) of destination grid point
  79. & coslon_dst, ! cos(lon) of destination grid point
  80. & sinlat_dst, ! sin(lat) of destination grid point
  81. & sinlon_dst, ! sin(lon) of destination grid point
  82. & dist_tot ! sum of neighbor distances (for normalizing)
  83. !-----------------------------------------------------------------------
  84. !
  85. ! compute mappings from grid1 to grid2
  86. !
  87. !-----------------------------------------------------------------------
  88. nmap = 1
  89. !***
  90. !*** allocate wgtstmp to be consistent with store_link interface
  91. !***
  92. allocate (wgtstmp(num_wts))
  93. !***
  94. !*** compute cos, sin of lat/lon on source grid for distance
  95. !*** calculations
  96. !***
  97. allocate (coslat(grid1_size), coslon(grid1_size),
  98. & sinlat(grid1_size), sinlon(grid1_size))
  99. coslat = cos(grid1_center_lat)
  100. coslon = cos(grid1_center_lon)
  101. sinlat = sin(grid1_center_lat)
  102. sinlon = sin(grid1_center_lon)
  103. !***
  104. !*** loop over destination grid
  105. !***
  106. grid_loop1: do dst_add = 1, grid2_size
  107. if (.not. grid2_mask(dst_add)) cycle grid_loop1
  108. coslat_dst = cos(grid2_center_lat(dst_add))
  109. coslon_dst = cos(grid2_center_lon(dst_add))
  110. sinlat_dst = sin(grid2_center_lat(dst_add))
  111. sinlon_dst = sin(grid2_center_lon(dst_add))
  112. !***
  113. !*** find nearest grid points on source grid and
  114. !*** distances to each point
  115. !***
  116. call grid_search_nbr(nbr_add, nbr_dist,
  117. & grid2_center_lat(dst_add),
  118. & grid2_center_lon(dst_add),
  119. & coslat_dst, coslon_dst,
  120. & sinlat_dst, sinlon_dst,
  121. & bin_addr1, bin_addr2)
  122. !***
  123. !*** compute weights based on inverse distance
  124. !*** if mask is false, eliminate those points
  125. !***
  126. dist_tot = zero
  127. do n=1,num_neighbors
  128. if (grid1_mask(nbr_add(n))) then
  129. nbr_dist(n) = one/nbr_dist(n)
  130. dist_tot = dist_tot + nbr_dist(n)
  131. nbr_mask(n) = .true.
  132. else
  133. nbr_mask(n) = .false.
  134. endif
  135. end do
  136. !***
  137. !*** normalize weights and store the link
  138. !***
  139. do n=1,num_neighbors
  140. if (nbr_mask(n)) then
  141. wgtstmp(1) = nbr_dist(n)/dist_tot
  142. call store_link_nbr(nbr_add(n), dst_add, wgtstmp, nmap)
  143. grid2_frac(dst_add) = one
  144. endif
  145. end do
  146. end do grid_loop1
  147. deallocate (coslat, coslon, sinlat, sinlon)
  148. !-----------------------------------------------------------------------
  149. !
  150. ! compute mappings from grid2 to grid1 if necessary
  151. !
  152. !-----------------------------------------------------------------------
  153. if (num_maps > 1) then
  154. nmap = 2
  155. !***
  156. !*** compute cos, sin of lat/lon on source grid for distance
  157. !*** calculations
  158. !***
  159. allocate (coslat(grid2_size), coslon(grid2_size),
  160. & sinlat(grid2_size), sinlon(grid2_size))
  161. coslat = cos(grid2_center_lat)
  162. coslon = cos(grid2_center_lon)
  163. sinlat = sin(grid2_center_lat)
  164. sinlon = sin(grid2_center_lon)
  165. !***
  166. !*** loop over destination grid
  167. !***
  168. grid_loop2: do dst_add = 1, grid1_size
  169. if (.not. grid1_mask(dst_add)) cycle grid_loop2
  170. coslat_dst = cos(grid1_center_lat(dst_add))
  171. coslon_dst = cos(grid1_center_lon(dst_add))
  172. sinlat_dst = sin(grid1_center_lat(dst_add))
  173. sinlon_dst = sin(grid1_center_lon(dst_add))
  174. !***
  175. !*** find four nearest grid points on source grid and
  176. !*** distances to each point
  177. !***
  178. call grid_search_nbr(nbr_add, nbr_dist,
  179. & grid1_center_lat(dst_add),
  180. & grid1_center_lon(dst_add),
  181. & coslat_dst, coslon_dst,
  182. & sinlat_dst, sinlon_dst,
  183. & bin_addr2, bin_addr1)
  184. !***
  185. !*** compute weights based on inverse distance
  186. !*** if mask is false, eliminate those points
  187. !***
  188. dist_tot = zero
  189. do n=1,num_neighbors
  190. if (grid2_mask(nbr_add(n))) then
  191. nbr_dist(n) = one/nbr_dist(n)
  192. dist_tot = dist_tot + nbr_dist(n)
  193. nbr_mask(n) = .true.
  194. else
  195. nbr_mask(n) = .false.
  196. endif
  197. end do
  198. !***
  199. !*** normalize weights and store the link
  200. !***
  201. do n=1,num_neighbors
  202. if (nbr_mask(n)) then
  203. wgtstmp(1) = nbr_dist(n)/dist_tot
  204. call store_link_nbr(dst_add, nbr_add(n), wgtstmp, nmap)
  205. grid1_frac(dst_add) = one
  206. endif
  207. end do
  208. end do grid_loop2
  209. deallocate (coslat, coslon, sinlat, sinlon)
  210. endif
  211. deallocate(wgtstmp)
  212. !-----------------------------------------------------------------------
  213. end subroutine remap_distwgt
  214. !***********************************************************************
  215. subroutine grid_search_nbr(nbr_add, nbr_dist, plat, plon,
  216. & coslat_dst, coslon_dst, sinlat_dst, sinlon_dst,
  217. & src_bin_add, dst_bin_add)
  218. !-----------------------------------------------------------------------
  219. !
  220. ! this routine finds the closest num_neighbor points to a search
  221. ! point and computes a distance to each of the neighbors.
  222. !
  223. !-----------------------------------------------------------------------
  224. !-----------------------------------------------------------------------
  225. !
  226. ! output variables
  227. !
  228. !-----------------------------------------------------------------------
  229. integer (kind=int_kind), dimension(num_neighbors), intent(out) ::
  230. & nbr_add ! address of each of the closest points
  231. real (kind=dbl_kind), dimension(num_neighbors), intent(out) ::
  232. & nbr_dist ! distance to each of the closest points
  233. !-----------------------------------------------------------------------
  234. !
  235. ! input variables
  236. !
  237. !-----------------------------------------------------------------------
  238. integer (kind=int_kind), dimension(:,:), intent(in) ::
  239. & src_bin_add, ! search bins for restricting search
  240. & dst_bin_add
  241. real (kind=dbl_kind), intent(in) ::
  242. & plat, ! latitude of the search point
  243. & plon, ! longitude of the search point
  244. & coslat_dst, ! cos(lat) of the search point
  245. & coslon_dst, ! cos(lon) of the search point
  246. & sinlat_dst, ! sin(lat) of the search point
  247. & sinlon_dst ! sin(lon) of the search point
  248. !-----------------------------------------------------------------------
  249. !
  250. ! local variables
  251. !
  252. !-----------------------------------------------------------------------
  253. integer (kind=int_kind) :: n, nmax, nadd, nchk, ! dummy indices
  254. & min_add, max_add, nm1, np1, i, j, ip1, im1, jp1, jm1
  255. real (kind=dbl_kind) ::
  256. & distance ! angular distance
  257. !-----------------------------------------------------------------------
  258. !
  259. ! loop over source grid and find nearest neighbors
  260. !
  261. !-----------------------------------------------------------------------
  262. !***
  263. !*** restrict the search using search bins
  264. !*** expand the bins to catch neighbors
  265. !***
  266. select case (restrict_type)
  267. case('latitude')
  268. do n=1,num_srch_bins
  269. if (plat >= bin_lats(1,n) .and. plat <= bin_lats(2,n)) then
  270. min_add = src_bin_add(1,n)
  271. max_add = src_bin_add(2,n)
  272. nm1 = max(n-1,1)
  273. np1 = min(n+1,num_srch_bins)
  274. min_add = min(min_add,src_bin_add(1,nm1))
  275. max_add = max(max_add,src_bin_add(2,nm1))
  276. min_add = min(min_add,src_bin_add(1,np1))
  277. max_add = max(max_add,src_bin_add(2,np1))
  278. endif
  279. end do
  280. case('latlon')
  281. n = 0
  282. nmax = nint(sqrt(real(num_srch_bins)))
  283. do j=1,nmax
  284. jp1 = min(j+1,nmax)
  285. jm1 = max(j-1,1)
  286. do i=1,nmax
  287. ip1 = min(i+1,nmax)
  288. im1 = max(i-1,1)
  289. n = n+1
  290. if (plat >= bin_lats(1,n) .and. plat <= bin_lats(2,n) .and.
  291. & plon >= bin_lons(1,n) .and. plon <= bin_lons(3,n)) then
  292. min_add = src_bin_add(1,n)
  293. max_add = src_bin_add(2,n)
  294. nm1 = (jm1-1)*nmax + im1
  295. np1 = (jp1-1)*nmax + ip1
  296. nm1 = max(nm1,1)
  297. np1 = min(np1,num_srch_bins)
  298. min_add = min(min_add,src_bin_add(1,nm1))
  299. max_add = max(max_add,src_bin_add(2,nm1))
  300. min_add = min(min_add,src_bin_add(1,np1))
  301. max_add = max(max_add,src_bin_add(2,np1))
  302. endif
  303. end do
  304. end do
  305. end select
  306. !***
  307. !*** initialize distance and address arrays
  308. !***
  309. nbr_add = 0
  310. nbr_dist = bignum
  311. do nadd=min_add,max_add
  312. !***
  313. !*** find distance to this point
  314. !***
  315. distance = acos(sinlat_dst*sinlat(nadd) +
  316. & coslat_dst*coslat(nadd)*
  317. & (coslon_dst*coslon(nadd) +
  318. & sinlon_dst*sinlon(nadd)) )
  319. !***
  320. !*** store the address and distance if this is one of the
  321. !*** smallest four so far
  322. !***
  323. check_loop: do nchk=1,num_neighbors
  324. if (distance .lt. nbr_dist(nchk)) then
  325. do n=num_neighbors,nchk+1,-1
  326. nbr_add(n) = nbr_add(n-1)
  327. nbr_dist(n) = nbr_dist(n-1)
  328. end do
  329. nbr_add(nchk) = nadd
  330. nbr_dist(nchk) = distance
  331. exit check_loop
  332. endif
  333. end do check_loop
  334. end do
  335. !-----------------------------------------------------------------------
  336. end subroutine grid_search_nbr
  337. !***********************************************************************
  338. subroutine store_link_nbr(add1, add2, weights, nmap)
  339. !-----------------------------------------------------------------------
  340. !
  341. ! this routine stores the address and weight for this link in
  342. ! the appropriate address and weight arrays and resizes those
  343. ! arrays if necessary.
  344. !
  345. !-----------------------------------------------------------------------
  346. !-----------------------------------------------------------------------
  347. !
  348. ! input variables
  349. !
  350. !-----------------------------------------------------------------------
  351. integer (kind=int_kind), intent(in) ::
  352. & add1, ! address on grid1
  353. & add2, ! address on grid2
  354. & nmap ! identifies which direction for mapping
  355. real (kind=dbl_kind), dimension(:), intent(in) ::
  356. & weights ! array of remapping weights for this link
  357. !-----------------------------------------------------------------------
  358. !
  359. ! increment number of links and check to see if remap arrays need
  360. ! to be increased to accomodate the new link. then store the
  361. ! link.
  362. !
  363. !-----------------------------------------------------------------------
  364. select case (nmap)
  365. case(1)
  366. num_links_map1 = num_links_map1 + 1
  367. if (num_links_map1 > max_links_map1)
  368. & call resize_remap_vars(1,resize_increment)
  369. grid1_add_map1(num_links_map1) = add1
  370. grid2_add_map1(num_links_map1) = add2
  371. wts_map1 (:,num_links_map1) = weights
  372. case(2)
  373. num_links_map2 = num_links_map2 + 1
  374. if (num_links_map2 > max_links_map2)
  375. & call resize_remap_vars(2,resize_increment)
  376. grid1_add_map2(num_links_map2) = add1
  377. grid2_add_map2(num_links_map2) = add2
  378. wts_map2 (:,num_links_map2) = weights
  379. end select
  380. !-----------------------------------------------------------------------
  381. end subroutine store_link_nbr
  382. !***********************************************************************
  383. end module remap_distance_weight
  384. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!