mod_grid.F90 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. module mod_grid
  2. ! Contains the type definition for regular (or irregular grids) together
  3. ! with a selection of subprograms for extracting information about the
  4. ! grid.
  5. !
  6. ! 28.1.99, Oyvind.Breivik@nrsc.no.
  7. !
  8. ! Future extensions: function checkgrid returns zero if grid contains errors
  9. ! or is not set. Include function overloading so that checkgrid may return both
  10. ! integer and real.
  11. !!! Module
  12. use mod_angles
  13. !!! Type definition
  14. ! Type grid contains information for constructing a 1D, 2D, or 3D grid. The
  15. ! grid may be periodic and physical units may be added to keep track of
  16. ! the physical dimensions of start points and resolution of the grid.
  17. !
  18. ! Oyvind Breivik, 30.12.98.
  19. type grid
  20. integer :: nx, ny, nz ! No of grid points
  21. real :: dx, dy, dz ! Resolution
  22. real :: x0, y0, z0 ! Start point (lower left)
  23. real :: undef ! Undefined value, typically 999.0
  24. integer :: order ! 1D, 2D or 3D grid? Default is 2.
  25. logical :: px, py, pz ! Periodic grid in x, y, z? Default is .false.
  26. logical :: reg ! Regular grid? Default is .true.
  27. ! If not, order should be 1, indicating an
  28. ! array of unevenly spaced data rather than a
  29. ! proper grid. In this case, resolution and
  30. ! start point become meaningless.
  31. logical :: set ! Grid initialized or containing default settings?
  32. character(len=10) :: ux, uy, uz ! Physical units, 'deg' denotes degrees,
  33. ! default is '1', nondimensional.
  34. end type grid
  35. type (grid), parameter :: default_grid = grid(0, 0, 0, 0.0, 0.0, &
  36. 0.0, 0.0, 0.0, 0.0, 999.0, 0, .false., .false., .false., &
  37. .true., .false., '1', '1', '1')
  38. contains
  39. !!! Subprograms
  40. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  41. function gridpoints(gr)
  42. ! Calculates the total number of grid points N in a regular grid of
  43. ! type grid or an irregular array of type grid. Returns zero if grid is not
  44. ! initialized.
  45. ! Oyvind Breivik, 30.12.98.
  46. !!! Interface
  47. integer gridpoints
  48. type (grid), intent (in) :: gr
  49. select case (gr%order)
  50. case (1)
  51. gridpoints = gr%nx
  52. case (2)
  53. gridpoints = gr%nx*gr%ny
  54. case (3)
  55. gridpoints = gr%nx*gr%ny*gr%nz
  56. end select
  57. if (.not. gr%reg) then ! Irregular grid?
  58. gridpoints = gr%nx
  59. end if
  60. if (.not. gr%set) then ! Grid initialized or containing default values?
  61. gridpoints = 0 ! If not initialized, return zero.
  62. end if
  63. end function gridpoints
  64. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  65. function gridindex(x,dimid,gr)
  66. ! Finds corresponding grid index for coordinate x for grid dimension dimid,
  67. ! where dimid = 1 denotes x, dimid = 2
  68. ! denotes y, and dimid = 3 denotes z. If dimid < 0, the grid index is
  69. ! rounded down using INT, so that the corresponding grid point is ``to
  70. ! the left'' of x. Otherwise NINT is used and the nearest grid point is
  71. ! found.
  72. !
  73. ! A return value of zero indicates that x is out of range or grid not
  74. ! initialized.
  75. ! Note that (x-x0) is mapped to [-180, 180] degrees if and only if the
  76. ! variable ux, uy, or uz (depending again on dimid) equals 'deg'. This is
  77. ! to ensure that crossing the zero longitude branch cut is handled correctly.
  78. ! A return value of -1 indicates that dimid is illegal (greater than the
  79. ! order of the grid).
  80. !
  81. ! Requires module mod_angles.
  82. !!! Interface
  83. integer gridindex
  84. real, intent (in) :: x
  85. integer, intent (in) :: dimid
  86. type (grid), intent (in) :: gr
  87. !!! Locals
  88. real :: x0, x1, dx, e
  89. integer :: nx
  90. logical :: closest, deg
  91. !!! Initialize
  92. closest = (dimid > 0)
  93. select case (abs(dimid)) ! Choose correct grid dimension
  94. case (1)
  95. x0 = gr%x0
  96. dx = gr%dx
  97. nx = gr%nx
  98. deg = (gr%ux == 'deg')
  99. case (2)
  100. x0 = gr%y0
  101. dx = gr%dy
  102. nx = gr%ny
  103. deg = (gr%uy == 'deg')
  104. case (3)
  105. x0 = gr%z0
  106. dx = gr%dz
  107. nx = gr%nz
  108. deg = (gr%uz == 'deg')
  109. end select
  110. x1 = x - x0
  111. if (closest) then
  112. e = dx/2 ! Small value epsilon
  113. else
  114. e = 0.0
  115. end if
  116. if (deg) then
  117. x1 = ang360(x1+e) ! Adding dx/2 is a trick to avoid the branch cut
  118. x1 = x1-e ! when finding the closest grid point.
  119. end if
  120. if (.not. closest) then
  121. x1 = x1 - dx/2 ! Round down
  122. end if
  123. gridindex = nint(x1/dx) + 1
  124. if (gridindex < 1 .or. gridindex > nx) then
  125. gridindex = 0
  126. end if
  127. if (abs(dimid) > gr%order) then
  128. gridindex = -1
  129. end if
  130. if (.not. gr%set) then
  131. gridindex = 0
  132. end if
  133. end function gridindex
  134. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  135. function gridpos(i,dimid,gr)
  136. ! Returns the position of grid node i along dimension dimid in grid.
  137. !
  138. ! If dimid < 0 and the physical unit of the grid is degrees,
  139. ! -180 <= gridpos < 180 [deg]. Otherwise, 0 <= gridpos < 360 [deg].
  140. !
  141. ! Requires module mod_angles.
  142. !!! Interface
  143. real gridpos
  144. integer, intent (in) :: i, dimid
  145. type (grid), intent (in) :: gr
  146. !!! Locals
  147. real x0, dx
  148. logical deg
  149. select case (abs(dimid))
  150. case (1)
  151. x0 = gr%x0
  152. dx = gr%dx
  153. deg = (gr%ux == 'deg')
  154. case (2)
  155. x0 = gr%y0
  156. dx = gr%dy
  157. deg = (gr%uy == 'deg')
  158. case (3)
  159. x0 = gr%z0
  160. dx = gr%dz
  161. deg = (gr%uz == 'deg')
  162. end select
  163. gridpos = x0 + real(i-1)*dx
  164. if (deg) then
  165. if (dimid < 0) then
  166. gridpos = ang180(gridpos)
  167. else
  168. gridpos = ang360(gridpos)
  169. end if
  170. end if
  171. end function gridpos
  172. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  173. function ingrid(x,dimid,gr)
  174. ! Is x within [x0, x1]? Here x0 and x1 denote the physical
  175. ! bounds of the grid along dimension dimid. If dimid < 0 then ingrid
  176. ! checks the interval [-dx/2+x0, x1+dx/2] instead.
  177. !
  178. ! Requires module mod_angles.
  179. !!! Interface
  180. logical ingrid
  181. real, intent (in) :: x
  182. integer, intent (in) :: dimid
  183. type (grid), intent (in) :: gr
  184. !!! Locals
  185. real x0, x1, dx
  186. integer nx
  187. logical deg
  188. select case (abs(dimid))
  189. case (1)
  190. dx = gr%dx
  191. x0 = gr%x0
  192. nx = gr%nx
  193. deg = (gr%ux == 'deg')
  194. case (2)
  195. dx = gr%dy
  196. x0 = gr%y0
  197. nx = gr%ny
  198. deg = (gr%uy == 'deg')
  199. case (3)
  200. dx = gr%dz
  201. x0 = gr%z0
  202. nx = gr%nz
  203. deg = (gr%uz == 'deg')
  204. end select
  205. x1 = gridpos(nx,dimid,gr)
  206. if (dimid < 0) then
  207. x0 = x0 - dx/2
  208. x1 = x1 + dx/2
  209. end if
  210. ingrid = (x0 <= x) .and. (x <= x1)
  211. if (deg) then
  212. ingrid = ang360(x1-x0) >= ang360(x-x0)
  213. end if
  214. ingrid = ingrid .and. gr%set
  215. end function ingrid
  216. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  217. function undefined(d,gr)
  218. ! True if d == gr%undef.
  219. logical undefined
  220. real, intent (in) :: d
  221. type (grid), intent (in) :: gr
  222. undefined = abs(d-gr%undef) < 0.01
  223. end function undefined
  224. end module mod_grid