PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/WPS/geogrid/src/module_map_utils.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 2210 lines | 1165 code | 507 blank | 538 comment | 37 complexity | 9089163e9f96298a6c09e995f476fd9e MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. MODULE map_utils
  2. ! Module that defines constants, data structures, and
  3. ! subroutines used to convert grid indices to lat/lon
  4. ! and vice versa.
  5. !
  6. ! SUPPORTED PROJECTIONS
  7. ! ---------------------
  8. ! Cylindrical Lat/Lon (code = PROJ_LATLON)
  9. ! Mercator (code = PROJ_MERC)
  10. ! Lambert Conformal (code = PROJ_LC)
  11. ! Gaussian (code = PROJ_GAUSS)
  12. ! Polar Stereographic (code = PROJ_PS)
  13. ! Rotated Lat/Lon (code = PROJ_ROTLL)
  14. !
  15. ! REMARKS
  16. ! -------
  17. ! The routines contained within were adapted from routines
  18. ! obtained from NCEP's w3 library. The original NCEP routines were less
  19. ! flexible (e.g., polar-stereo routines only supported truelat of 60N/60S)
  20. ! than what we needed, so modifications based on equations in Hoke, Hayes, and
  21. ! Renninger (AFGWC/TN/79-003) were added to improve the flexibility.
  22. ! Additionally, coding was improved to F90 standards and the routines were
  23. ! combined into this module.
  24. !
  25. ! ASSUMPTIONS
  26. ! -----------
  27. ! Grid Definition:
  28. ! For mercator, lambert conformal, and polar-stereographic projections,
  29. ! the routines within assume the following:
  30. !
  31. ! 1. Grid is dimensioned (i,j) where i is the East-West direction,
  32. ! positive toward the east, and j is the north-south direction,
  33. ! positive toward the north.
  34. ! 2. Origin is at (1,1) and is located at the southwest corner,
  35. ! regardless of hemispere.
  36. ! 3. Grid spacing (dx) is always positive.
  37. ! 4. Values of true latitudes must be positive for NH domains
  38. ! and negative for SH domains.
  39. !
  40. ! For the latlon and Gaussian projection, the grid origin may be at any
  41. ! of the corners, and the deltalat and deltalon values can be signed to
  42. ! account for this using the following convention:
  43. ! Origin Location Deltalat Sign Deltalon Sign
  44. ! --------------- ------------- -------------
  45. ! SW Corner + +
  46. ! NE Corner - -
  47. ! NW Corner - +
  48. ! SE Corner + -
  49. !
  50. ! Data Definitions:
  51. ! 1. Any arguments that are a latitude value are expressed in
  52. ! degrees north with a valid range of -90 -> 90
  53. ! 2. Any arguments that are a longitude value are expressed in
  54. ! degrees east with a valid range of -180 -> 180.
  55. ! 3. Distances are in meters and are always positive.
  56. ! 4. The standard longitude (stdlon) is defined as the longitude
  57. ! line which is parallel to the grid's y-axis (j-direction), along
  58. ! which latitude increases (NOT the absolute value of latitude, but
  59. ! the actual latitude, such that latitude increases continuously
  60. ! from the south pole to the north pole) as j increases.
  61. ! 5. One true latitude value is required for polar-stereographic and
  62. ! mercator projections, and defines at which latitude the
  63. ! grid spacing is true. For lambert conformal, two true latitude
  64. ! values must be specified, but may be set equal to each other to
  65. ! specify a tangent projection instead of a secant projection.
  66. !
  67. ! USAGE
  68. ! -----
  69. ! To use the routines in this module, the calling routines must have the
  70. ! following statement at the beginning of its declaration block:
  71. ! USE map_utils
  72. !
  73. ! The use of the module not only provides access to the necessary routines,
  74. ! but also defines a structure of TYPE (proj_info) that can be used
  75. ! to declare a variable of the same type to hold your map projection
  76. ! information. It also defines some integer parameters that contain
  77. ! the projection codes so one only has to use those variable names rather
  78. ! than remembering the acutal code when using them. The basic steps are
  79. ! as follows:
  80. !
  81. ! 1. Ensure the "USE map_utils" is in your declarations.
  82. ! 2. Declare the projection information structure as type(proj_info):
  83. ! TYPE(proj_info) :: proj
  84. ! 3. Populate your structure by calling the map_set routine:
  85. ! CALL map_set(code,lat1,lon1,knowni,knownj,dx,stdlon,truelat1,truelat2,proj)
  86. ! where:
  87. ! code (input) = one of PROJ_LATLON, PROJ_MERC, PROJ_LC, PROJ_PS,
  88. ! PROJ_GAUSS, or PROJ_ROTLL
  89. ! lat1 (input) = Latitude of grid origin point (i,j)=(1,1)
  90. ! (see assumptions!)
  91. ! lon1 (input) = Longitude of grid origin
  92. ! knowni (input) = origin point, x-location
  93. ! knownj (input) = origin point, y-location
  94. ! dx (input) = grid spacing in meters (ignored for LATLON projections)
  95. ! stdlon (input) = Standard longitude for PROJ_PS and PROJ_LC,
  96. ! deltalon (see assumptions) for PROJ_LATLON,
  97. ! ignored for PROJ_MERC
  98. ! truelat1 (input) = 1st true latitude for PROJ_PS, PROJ_LC, and
  99. ! PROJ_MERC, deltalat (see assumptions) for PROJ_LATLON
  100. ! truelat2 (input) = 2nd true latitude for PROJ_LC,
  101. ! ignored for all others.
  102. ! proj (output) = The structure of type (proj_info) that will be fully
  103. ! populated after this call
  104. !
  105. ! 4. Now that the proj structure is populated, you may call either
  106. ! of the following routines:
  107. !
  108. ! latlon_to_ij(proj, lat, lon, i, j)
  109. ! ij_to_latlon(proj, i, j, lat, lon)
  110. !
  111. ! It is incumbent upon the calling routine to determine whether or
  112. ! not the values returned are within your domain's bounds. All values
  113. ! of i, j, lat, and lon are REAL values.
  114. !
  115. !
  116. ! REFERENCES
  117. ! ----------
  118. ! Hoke, Hayes, and Renninger, "Map Preojections and Grid Systems for
  119. ! Meteorological Applications." AFGWC/TN-79/003(Rev), Air Weather
  120. ! Service, 1985.
  121. !
  122. ! NCAR MM5v3 Modeling System, REGRIDDER program, module_first_guess_map.F
  123. ! NCEP routines w3fb06, w3fb07, w3fb08, w3fb09, w3fb11, w3fb12
  124. !
  125. ! HISTORY
  126. ! -------
  127. ! 27 Mar 2001 - Original Version
  128. ! Brent L. Shaw, NOAA/FSL (CSU/CIRA)
  129. !
  130. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  131. use constants_module
  132. use misc_definitions_module
  133. use module_debug
  134. ! Define some private constants
  135. INTEGER, PRIVATE, PARAMETER :: HIGH = 8
  136. TYPE proj_info
  137. INTEGER :: code ! Integer code for projection TYPE
  138. INTEGER :: nlat ! For Gaussian -- number of latitude points
  139. ! north of the equator
  140. INTEGER :: nlon !
  141. !
  142. INTEGER :: nxmin ! Starting x-coordinate of periodic, regular lat/lon dataset
  143. INTEGER :: nxmax ! Ending x-coordinate of periodic, regular lat/lon dataset
  144. INTEGER :: ixdim ! For Rotated Lat/Lon -- number of mass points
  145. ! in an odd row
  146. INTEGER :: jydim ! For Rotated Lat/Lon -- number of rows
  147. INTEGER :: stagger ! For Rotated Lat/Lon -- mass or velocity grid
  148. REAL :: phi ! For Rotated Lat/Lon -- domain half-extent in
  149. ! degrees latitude
  150. REAL :: lambda ! For Rotated Lat/Lon -- domain half-extend in
  151. ! degrees longitude
  152. REAL :: lat1 ! SW latitude (1,1) in degrees (-90->90N)
  153. REAL :: lon1 ! SW longitude (1,1) in degrees (-180->180E)
  154. REAL :: lat0 ! For Cassini, latitude of projection pole
  155. REAL :: lon0 ! For Cassini, longitude of projection pole
  156. REAL :: dx ! Grid spacing in meters at truelats, used
  157. ! only for ps, lc, and merc projections
  158. REAL :: dy ! Grid spacing in meters at truelats, used
  159. ! only for ps, lc, and merc projections
  160. REAL :: latinc ! Latitude increment for cylindrical lat/lon
  161. REAL :: loninc ! Longitude increment for cylindrical lat/lon
  162. ! also the lon increment for Gaussian grid
  163. REAL :: dlat ! Lat increment for lat/lon grids
  164. REAL :: dlon ! Lon increment for lat/lon grids
  165. REAL :: stdlon ! Longitude parallel to y-axis (-180->180E)
  166. REAL :: truelat1 ! First true latitude (all projections)
  167. REAL :: truelat2 ! Second true lat (LC only)
  168. REAL :: hemi ! 1 for NH, -1 for SH
  169. REAL :: cone ! Cone factor for LC projections
  170. REAL :: polei ! Computed i-location of pole point
  171. REAL :: polej ! Computed j-location of pole point
  172. REAL :: rsw ! Computed radius to SW corner
  173. REAL :: rebydx ! Earth radius divided by dx
  174. REAL :: knowni ! X-location of known lat/lon
  175. REAL :: knownj ! Y-location of known lat/lon
  176. REAL :: re_m ! Radius of spherical earth, meters
  177. REAL :: rho0 ! For Albers equal area
  178. REAL :: nc ! For Albers equal area
  179. REAL :: bigc ! For Albers equal area
  180. LOGICAL :: init ! Flag to indicate if this struct is
  181. ! ready for use
  182. LOGICAL :: wrap ! For Gaussian -- flag to indicate wrapping
  183. ! around globe?
  184. LOGICAL :: comp_ll ! Work in computational lat/lon space for Cassini
  185. REAL, POINTER, DIMENSION(:) :: gauss_lat ! Latitude array for Gaussian grid
  186. END TYPE proj_info
  187. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  188. CONTAINS
  189. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  190. SUBROUTINE map_init(proj)
  191. ! Initializes the map projection structure to missing values
  192. IMPLICIT NONE
  193. TYPE(proj_info), INTENT(INOUT) :: proj
  194. proj%lat1 = -999.9
  195. proj%lon1 = -999.9
  196. proj%lat0 = -999.9
  197. proj%lon0 = -999.9
  198. proj%dx = -999.9
  199. proj%dy = -999.9
  200. proj%latinc = -999.9
  201. proj%loninc = -999.9
  202. proj%stdlon = -999.9
  203. proj%truelat1 = -999.9
  204. proj%truelat2 = -999.9
  205. proj%phi = -999.9
  206. proj%lambda = -999.9
  207. proj%ixdim = -999
  208. proj%jydim = -999
  209. proj%stagger = HH
  210. proj%nlat = 0
  211. proj%nlon = 0
  212. proj%nxmin = 1
  213. proj%nxmax = 43200
  214. proj%hemi = 0.0
  215. proj%cone = -999.9
  216. proj%polei = -999.9
  217. proj%polej = -999.9
  218. proj%rsw = -999.9
  219. proj%knowni = -999.9
  220. proj%knownj = -999.9
  221. proj%re_m = EARTH_RADIUS_M
  222. proj%init = .FALSE.
  223. proj%wrap = .FALSE.
  224. proj%rho0 = 0.
  225. proj%nc = 0.
  226. proj%bigc = 0.
  227. proj%comp_ll = .FALSE.
  228. nullify(proj%gauss_lat)
  229. END SUBROUTINE map_init
  230. SUBROUTINE map_set(proj_code, proj, lat1, lon1, lat0, lon0, knowni, knownj, dx, dy, latinc, &
  231. loninc, stdlon, truelat1, truelat2, nlat, nlon, ixdim, jydim, nxmin, nxmax, &
  232. stagger, phi, lambda, r_earth)
  233. ! Given a partially filled proj_info structure, this routine computes
  234. ! polei, polej, rsw, and cone (if LC projection) to complete the
  235. ! structure. This allows us to eliminate redundant calculations when
  236. ! calling the coordinate conversion routines multiple times for the
  237. ! same map.
  238. ! This will generally be the first routine called when a user wants
  239. ! to be able to use the coordinate conversion routines, and it
  240. ! will call the appropriate subroutines based on the
  241. ! proj%code which indicates which projection type this is.
  242. IMPLICIT NONE
  243. ! Declare arguments
  244. INTEGER, INTENT(IN) :: proj_code
  245. INTEGER, INTENT(IN), OPTIONAL :: nlat
  246. INTEGER, INTENT(IN), OPTIONAL :: nlon
  247. INTEGER, INTENT(IN), OPTIONAL :: ixdim
  248. INTEGER, INTENT(IN), OPTIONAL :: jydim
  249. INTEGER, INTENT(IN), OPTIONAL :: nxmin
  250. INTEGER, INTENT(IN), OPTIONAL :: nxmax
  251. INTEGER, INTENT(IN), OPTIONAL :: stagger
  252. REAL, INTENT(IN), OPTIONAL :: latinc
  253. REAL, INTENT(IN), OPTIONAL :: loninc
  254. REAL, INTENT(IN), OPTIONAL :: lat1
  255. REAL, INTENT(IN), OPTIONAL :: lon1
  256. REAL, INTENT(IN), OPTIONAL :: lat0
  257. REAL, INTENT(IN), OPTIONAL :: lon0
  258. REAL, INTENT(IN), OPTIONAL :: dx
  259. REAL, INTENT(IN), OPTIONAL :: dy
  260. REAL, INTENT(IN), OPTIONAL :: stdlon
  261. REAL, INTENT(IN), OPTIONAL :: truelat1
  262. REAL, INTENT(IN), OPTIONAL :: truelat2
  263. REAL, INTENT(IN), OPTIONAL :: knowni
  264. REAL, INTENT(IN), OPTIONAL :: knownj
  265. REAL, INTENT(IN), OPTIONAL :: phi
  266. REAL, INTENT(IN), OPTIONAL :: lambda
  267. REAL, INTENT(IN), OPTIONAL :: r_earth
  268. TYPE(proj_info), INTENT(OUT) :: proj
  269. INTEGER :: iter
  270. REAL :: dummy_lon1
  271. REAL :: dummy_lon0
  272. REAL :: dummy_stdlon
  273. ! First, verify that mandatory parameters are present for the specified proj_code
  274. IF ( proj_code == PROJ_LC ) THEN
  275. IF ( .NOT.PRESENT(truelat1) .OR. &
  276. .NOT.PRESENT(truelat2) .OR. &
  277. .NOT.PRESENT(lat1) .OR. &
  278. .NOT.PRESENT(lon1) .OR. &
  279. .NOT.PRESENT(knowni) .OR. &
  280. .NOT.PRESENT(knownj) .OR. &
  281. .NOT.PRESENT(stdlon) .OR. &
  282. .NOT.PRESENT(dx) ) THEN
  283. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  284. PRINT '(A)', ' truelat1, truelat2, lat1, lon1, knowni, knownj, stdlon, dx'
  285. call mprintf(.true.,ERROR,'MAP_INIT')
  286. END IF
  287. ELSE IF ( proj_code == PROJ_PS ) THEN
  288. IF ( .NOT.PRESENT(truelat1) .OR. &
  289. .NOT.PRESENT(lat1) .OR. &
  290. .NOT.PRESENT(lon1) .OR. &
  291. .NOT.PRESENT(knowni) .OR. &
  292. .NOT.PRESENT(knownj) .OR. &
  293. .NOT.PRESENT(stdlon) .OR. &
  294. .NOT.PRESENT(dx) ) THEN
  295. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  296. PRINT '(A)', ' truelat1, lat1, lon1, knonwi, knownj, stdlon, dx'
  297. call mprintf(.true.,ERROR,'MAP_INIT')
  298. END IF
  299. ELSE IF ( proj_code == PROJ_PS_WGS84 ) THEN
  300. IF ( .NOT.PRESENT(truelat1) .OR. &
  301. .NOT.PRESENT(lat1) .OR. &
  302. .NOT.PRESENT(lon1) .OR. &
  303. .NOT.PRESENT(knowni) .OR. &
  304. .NOT.PRESENT(knownj) .OR. &
  305. .NOT.PRESENT(stdlon) .OR. &
  306. .NOT.PRESENT(dx) ) THEN
  307. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  308. PRINT '(A)', ' truelat1, lat1, lon1, knonwi, knownj, stdlon, dx'
  309. call mprintf(.true.,ERROR,'MAP_INIT')
  310. END IF
  311. ELSE IF ( proj_code == PROJ_ALBERS_NAD83 ) THEN
  312. IF ( .NOT.PRESENT(truelat1) .OR. &
  313. .NOT.PRESENT(truelat2) .OR. &
  314. .NOT.PRESENT(lat1) .OR. &
  315. .NOT.PRESENT(lon1) .OR. &
  316. .NOT.PRESENT(knowni) .OR. &
  317. .NOT.PRESENT(knownj) .OR. &
  318. .NOT.PRESENT(stdlon) .OR. &
  319. .NOT.PRESENT(dx) ) THEN
  320. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  321. PRINT '(A)', ' truelat1, truelat2, lat1, lon1, knonwi, knownj, stdlon, dx'
  322. call mprintf(.true.,ERROR,'MAP_INIT')
  323. END IF
  324. ELSE IF ( proj_code == PROJ_MERC ) THEN
  325. IF ( .NOT.PRESENT(truelat1) .OR. &
  326. .NOT.PRESENT(lat1) .OR. &
  327. .NOT.PRESENT(lon1) .OR. &
  328. .NOT.PRESENT(knowni) .OR. &
  329. .NOT.PRESENT(knownj) .OR. &
  330. .NOT.PRESENT(dx) ) THEN
  331. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  332. PRINT '(A)', ' truelat1, lat1, lon1, knowni, knownj, dx'
  333. call mprintf(.true.,ERROR,'MAP_INIT')
  334. END IF
  335. ELSE IF ( proj_code == PROJ_LATLON ) THEN
  336. IF ( .NOT.PRESENT(latinc) .OR. &
  337. .NOT.PRESENT(loninc) .OR. &
  338. .NOT.PRESENT(knowni) .OR. &
  339. .NOT.PRESENT(knownj) .OR. &
  340. .NOT.PRESENT(lat1) .OR. &
  341. .NOT.PRESENT(lon1) ) THEN
  342. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  343. PRINT '(A)', ' latinc, loninc, knowni, knownj, lat1, lon1'
  344. call mprintf(.true.,ERROR,'MAP_INIT')
  345. END IF
  346. ELSE IF ( proj_code == PROJ_CYL ) THEN
  347. IF ( .NOT.PRESENT(latinc) .OR. &
  348. .NOT.PRESENT(loninc) .OR. &
  349. .NOT.PRESENT(stdlon) ) THEN
  350. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  351. PRINT '(A)', ' latinc, loninc, stdlon'
  352. call mprintf(.true.,ERROR,'MAP_INIT')
  353. END IF
  354. ELSE IF ( proj_code == PROJ_CASSINI ) THEN
  355. IF ( .NOT.PRESENT(latinc) .OR. &
  356. .NOT.PRESENT(loninc) .OR. &
  357. .NOT.PRESENT(lat1) .OR. &
  358. .NOT.PRESENT(lon1) .OR. &
  359. .NOT.PRESENT(lat0) .OR. &
  360. .NOT.PRESENT(lon0) .OR. &
  361. .NOT.PRESENT(knowni) .OR. &
  362. .NOT.PRESENT(knownj) .OR. &
  363. .NOT.PRESENT(stdlon) ) THEN
  364. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  365. PRINT '(A)', ' latinc, loninc, lat1, lon1, knowni, knownj, lat0, lon0, stdlon'
  366. call mprintf(.true.,ERROR,'MAP_INIT')
  367. END IF
  368. ELSE IF ( proj_code == PROJ_GAUSS ) THEN
  369. IF ( .NOT.PRESENT(nlat) .OR. &
  370. .NOT.PRESENT(lat1) .OR. &
  371. .NOT.PRESENT(lon1) .OR. &
  372. .NOT.PRESENT(loninc) ) THEN
  373. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  374. PRINT '(A)', ' nlat, lat1, lon1, loninc'
  375. call mprintf(.true.,ERROR,'MAP_INIT')
  376. END IF
  377. ELSE IF ( proj_code == PROJ_ROTLL ) THEN
  378. IF ( .NOT.PRESENT(ixdim) .OR. &
  379. .NOT.PRESENT(jydim) .OR. &
  380. .NOT.PRESENT(phi) .OR. &
  381. .NOT.PRESENT(lambda) .OR. &
  382. .NOT.PRESENT(lat1) .OR. &
  383. .NOT.PRESENT(lon1) .OR. &
  384. .NOT.PRESENT(stagger) ) THEN
  385. PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
  386. PRINT '(A)', ' ixdim, jydim, phi, lambda, lat1, lon1, stagger'
  387. call mprintf(.true.,ERROR,'MAP_INIT')
  388. END IF
  389. ELSE
  390. PRINT '(A,I2)', 'Unknown projection code: ', proj_code
  391. call mprintf(.true.,ERROR,'MAP_INIT')
  392. END IF
  393. ! Check for validity of mandatory variables in proj
  394. IF ( PRESENT(lat1) ) THEN
  395. IF ( ABS(lat1) .GT. 90. ) THEN
  396. PRINT '(A)', 'Latitude of origin corner required as follows:'
  397. PRINT '(A)', ' -90N <= lat1 < = 90.N'
  398. call mprintf(.true.,ERROR,'MAP_INIT')
  399. ENDIF
  400. ENDIF
  401. IF ( PRESENT(lon1) ) THEN
  402. dummy_lon1 = lon1
  403. IF ( ABS(dummy_lon1) .GT. 180.) THEN
  404. iter = 0
  405. DO WHILE (ABS(dummy_lon1) > 180. .AND. iter < 10)
  406. IF (dummy_lon1 < -180.) dummy_lon1 = dummy_lon1 + 360.
  407. IF (dummy_lon1 > 180.) dummy_lon1 = dummy_lon1 - 360.
  408. iter = iter + 1
  409. END DO
  410. IF (abs(dummy_lon1) > 180.) THEN
  411. PRINT '(A)', 'Longitude of origin required as follows:'
  412. PRINT '(A)', ' -180E <= lon1 <= 180W'
  413. call mprintf(.true.,ERROR,'MAP_INIT')
  414. ENDIF
  415. ENDIF
  416. ENDIF
  417. IF ( PRESENT(lon0) ) THEN
  418. dummy_lon0 = lon0
  419. IF ( ABS(dummy_lon0) .GT. 180.) THEN
  420. iter = 0
  421. DO WHILE (ABS(dummy_lon0) > 180. .AND. iter < 10)
  422. IF (dummy_lon0 < -180.) dummy_lon0 = dummy_lon0 + 360.
  423. IF (dummy_lon0 > 180.) dummy_lon0 = dummy_lon0 - 360.
  424. iter = iter + 1
  425. END DO
  426. IF (abs(dummy_lon0) > 180.) THEN
  427. PRINT '(A)', 'Longitude of pole required as follows:'
  428. PRINT '(A)', ' -180E <= lon0 <= 180W'
  429. call mprintf(.true.,ERROR,'MAP_INIT')
  430. ENDIF
  431. ENDIF
  432. ENDIF
  433. IF ( PRESENT(dx) ) THEN
  434. IF ((dx .LE. 0.).AND.(proj_code .NE. PROJ_LATLON)) THEN
  435. PRINT '(A)', 'Require grid spacing (dx) in meters be positive!'
  436. call mprintf(.true.,ERROR,'MAP_INIT')
  437. ENDIF
  438. ENDIF
  439. IF ( PRESENT(stdlon) ) THEN
  440. dummy_stdlon = stdlon
  441. IF ((ABS(dummy_stdlon) > 180.).AND.(proj_code /= PROJ_MERC)) THEN
  442. iter = 0
  443. DO WHILE (ABS(dummy_stdlon) > 180. .AND. iter < 10)
  444. IF (dummy_stdlon < -180.) dummy_stdlon = dummy_stdlon + 360.
  445. IF (dummy_stdlon > 180.) dummy_stdlon = dummy_stdlon - 360.
  446. iter = iter + 1
  447. END DO
  448. IF (abs(dummy_stdlon) > 180.) THEN
  449. PRINT '(A)', 'Need orientation longitude (stdlon) as: '
  450. PRINT '(A)', ' -180E <= stdlon <= 180W'
  451. call mprintf(.true.,ERROR,'MAP_INIT')
  452. ENDIF
  453. ENDIF
  454. ENDIF
  455. IF ( PRESENT(truelat1) ) THEN
  456. IF (ABS(truelat1).GT.90.) THEN
  457. PRINT '(A)', 'Set true latitude 1 for all projections!'
  458. call mprintf(.true.,ERROR,'MAP_INIT')
  459. ENDIF
  460. ENDIF
  461. CALL map_init(proj)
  462. proj%code = proj_code
  463. IF ( PRESENT(lat1) ) proj%lat1 = lat1
  464. IF ( PRESENT(lon1) ) proj%lon1 = dummy_lon1
  465. IF ( PRESENT(lat0) ) proj%lat0 = lat0
  466. IF ( PRESENT(lon0) ) proj%lon0 = dummy_lon0
  467. IF ( PRESENT(latinc) ) proj%latinc = latinc
  468. IF ( PRESENT(loninc) ) proj%loninc = loninc
  469. IF ( PRESENT(knowni) ) proj%knowni = knowni
  470. IF ( PRESENT(knownj) ) proj%knownj = knownj
  471. IF ( PRESENT(nxmin) ) proj%nxmin = nxmin
  472. IF ( PRESENT(nxmax) ) proj%nxmax = nxmax
  473. IF ( PRESENT(dx) ) proj%dx = dx
  474. IF ( PRESENT(dy) ) THEN
  475. proj%dy = dy
  476. ELSE IF ( PRESENT(dx) ) THEN
  477. proj%dy = dx
  478. END IF
  479. IF ( PRESENT(stdlon) ) proj%stdlon = dummy_stdlon
  480. IF ( PRESENT(truelat1) ) proj%truelat1 = truelat1
  481. IF ( PRESENT(truelat2) ) proj%truelat2 = truelat2
  482. IF ( PRESENT(nlat) ) proj%nlat = nlat
  483. IF ( PRESENT(nlon) ) proj%nlon = nlon
  484. IF ( PRESENT(ixdim) ) proj%ixdim = ixdim
  485. IF ( PRESENT(jydim) ) proj%jydim = jydim
  486. IF ( PRESENT(stagger) ) proj%stagger = stagger
  487. IF ( PRESENT(phi) ) proj%phi = phi
  488. IF ( PRESENT(lambda) ) proj%lambda = lambda
  489. IF ( PRESENT(r_earth) ) proj%re_m = r_earth
  490. IF ( PRESENT(dx) ) THEN
  491. IF ( (proj_code == PROJ_LC) .OR. (proj_code == PROJ_PS) .OR. &
  492. (proj_code == PROJ_PS_WGS84) .OR. (proj_code == PROJ_ALBERS_NAD83) .OR. &
  493. (proj_code == PROJ_MERC) ) THEN
  494. proj%dx = dx
  495. IF (truelat1 .LT. 0.) THEN
  496. proj%hemi = -1.0
  497. ELSE
  498. proj%hemi = 1.0
  499. ENDIF
  500. proj%rebydx = proj%re_m / dx
  501. ENDIF
  502. ENDIF
  503. pick_proj: SELECT CASE(proj%code)
  504. CASE(PROJ_PS)
  505. CALL set_ps(proj)
  506. CASE(PROJ_PS_WGS84)
  507. CALL set_ps_wgs84(proj)
  508. CASE(PROJ_ALBERS_NAD83)
  509. CALL set_albers_nad83(proj)
  510. CASE(PROJ_LC)
  511. IF (ABS(proj%truelat2) .GT. 90.) THEN
  512. proj%truelat2=proj%truelat1
  513. ENDIF
  514. CALL set_lc(proj)
  515. CASE (PROJ_MERC)
  516. CALL set_merc(proj)
  517. CASE (PROJ_LATLON)
  518. CASE (PROJ_GAUSS)
  519. CALL set_gauss(proj)
  520. CASE (PROJ_CYL)
  521. CALL set_cyl(proj)
  522. CASE (PROJ_CASSINI)
  523. CALL set_cassini(proj)
  524. CASE (PROJ_ROTLL)
  525. END SELECT pick_proj
  526. proj%init = .TRUE.
  527. RETURN
  528. END SUBROUTINE map_set
  529. SUBROUTINE latlon_to_ij(proj, lat, lon, i, j)
  530. ! Converts input lat/lon values to the cartesian (i,j) value
  531. ! for the given projection.
  532. IMPLICIT NONE
  533. TYPE(proj_info), INTENT(IN) :: proj
  534. REAL, INTENT(IN) :: lat
  535. REAL, INTENT(IN) :: lon
  536. REAL, INTENT(OUT) :: i
  537. REAL, INTENT(OUT) :: j
  538. IF (.NOT.proj%init) THEN
  539. PRINT '(A)', 'You have not called map_set for this projection!'
  540. call mprintf(.true.,ERROR,'LATLON_TO_IJ')
  541. ENDIF
  542. SELECT CASE(proj%code)
  543. CASE(PROJ_LATLON)
  544. CALL llij_latlon(lat,lon,proj,i,j)
  545. CASE(PROJ_MERC)
  546. CALL llij_merc(lat,lon,proj,i,j)
  547. CASE(PROJ_PS)
  548. CALL llij_ps(lat,lon,proj,i,j)
  549. CASE(PROJ_PS_WGS84)
  550. CALL llij_ps_wgs84(lat,lon,proj,i,j)
  551. CASE(PROJ_ALBERS_NAD83)
  552. CALL llij_albers_nad83(lat,lon,proj,i,j)
  553. CASE(PROJ_LC)
  554. CALL llij_lc(lat,lon,proj,i,j)
  555. CASE(PROJ_GAUSS)
  556. CALL llij_gauss(lat,lon,proj,i,j)
  557. CASE(PROJ_CYL)
  558. CALL llij_cyl(lat,lon,proj,i,j)
  559. CASE(PROJ_CASSINI)
  560. CALL llij_cassini(lat,lon,proj,i,j)
  561. CASE(PROJ_ROTLL)
  562. CALL llij_rotlatlon(lat,lon,proj,i,j)
  563. CASE DEFAULT
  564. PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code
  565. call mprintf(.true.,ERROR,'LATLON_TO_IJ')
  566. END SELECT
  567. RETURN
  568. END SUBROUTINE latlon_to_ij
  569. SUBROUTINE ij_to_latlon(proj, i, j, lat, lon)
  570. ! Computes geographical latitude and longitude for a given (i,j) point
  571. ! in a grid with a projection of proj
  572. IMPLICIT NONE
  573. TYPE(proj_info),INTENT(IN) :: proj
  574. REAL, INTENT(IN) :: i
  575. REAL, INTENT(IN) :: j
  576. REAL, INTENT(OUT) :: lat
  577. REAL, INTENT(OUT) :: lon
  578. IF (.NOT.proj%init) THEN
  579. PRINT '(A)', 'You have not called map_set for this projection!'
  580. call mprintf(.true.,ERROR,'IJ_TO_LATLON')
  581. ENDIF
  582. SELECT CASE (proj%code)
  583. CASE (PROJ_LATLON)
  584. CALL ijll_latlon(i, j, proj, lat, lon)
  585. CASE (PROJ_MERC)
  586. CALL ijll_merc(i, j, proj, lat, lon)
  587. CASE (PROJ_PS)
  588. CALL ijll_ps(i, j, proj, lat, lon)
  589. CASE (PROJ_PS_WGS84)
  590. CALL ijll_ps_wgs84(i, j, proj, lat, lon)
  591. CASE (PROJ_ALBERS_NAD83)
  592. CALL ijll_albers_nad83(i, j, proj, lat, lon)
  593. CASE (PROJ_LC)
  594. CALL ijll_lc(i, j, proj, lat, lon)
  595. CASE (PROJ_CYL)
  596. CALL ijll_cyl(i, j, proj, lat, lon)
  597. CASE (PROJ_CASSINI)
  598. CALL ijll_cassini(i, j, proj, lat, lon)
  599. CASE (PROJ_ROTLL)
  600. CALL ijll_rotlatlon(i, j, proj, lat, lon)
  601. CASE DEFAULT
  602. PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code
  603. call mprintf(.true.,ERROR,'IJ_TO_LATLON')
  604. END SELECT
  605. RETURN
  606. END SUBROUTINE ij_to_latlon
  607. SUBROUTINE set_ps(proj)
  608. ! Initializes a polar-stereographic map projection from the partially
  609. ! filled proj structure. This routine computes the radius to the
  610. ! southwest corner and computes the i/j location of the pole for use
  611. ! in llij_ps and ijll_ps.
  612. IMPLICIT NONE
  613. ! Declare args
  614. TYPE(proj_info), INTENT(INOUT) :: proj
  615. ! Local vars
  616. REAL :: ala1
  617. REAL :: alo1
  618. REAL :: reflon
  619. REAL :: scale_top
  620. ! Executable code
  621. reflon = proj%stdlon + 90.
  622. ! Compute numerator term of map scale factor
  623. scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
  624. ! Compute radius to lower-left (SW) corner
  625. ala1 = proj%lat1 * rad_per_deg
  626. proj%rsw = proj%rebydx*COS(ala1)*scale_top/(1.+proj%hemi*SIN(ala1))
  627. ! Find the pole point
  628. alo1 = (proj%lon1 - reflon) * rad_per_deg
  629. proj%polei = proj%knowni - proj%rsw * COS(alo1)
  630. proj%polej = proj%knownj - proj%hemi * proj%rsw * SIN(alo1)
  631. RETURN
  632. END SUBROUTINE set_ps
  633. SUBROUTINE llij_ps(lat,lon,proj,i,j)
  634. ! Given latitude (-90 to 90), longitude (-180 to 180), and the
  635. ! standard polar-stereographic projection information via the
  636. ! public proj structure, this routine returns the i/j indices which
  637. ! if within the domain range from 1->nx and 1->ny, respectively.
  638. IMPLICIT NONE
  639. ! Delcare input arguments
  640. REAL, INTENT(IN) :: lat
  641. REAL, INTENT(IN) :: lon
  642. TYPE(proj_info),INTENT(IN) :: proj
  643. ! Declare output arguments
  644. REAL, INTENT(OUT) :: i !(x-index)
  645. REAL, INTENT(OUT) :: j !(y-index)
  646. ! Declare local variables
  647. REAL :: reflon
  648. REAL :: scale_top
  649. REAL :: ala
  650. REAL :: alo
  651. REAL :: rm
  652. ! BEGIN CODE
  653. reflon = proj%stdlon + 90.
  654. ! Compute numerator term of map scale factor
  655. scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
  656. ! Find radius to desired point
  657. ala = lat * rad_per_deg
  658. rm = proj%rebydx * COS(ala) * scale_top/(1. + proj%hemi *SIN(ala))
  659. alo = (lon - reflon) * rad_per_deg
  660. i = proj%polei + rm * COS(alo)
  661. j = proj%polej + proj%hemi * rm * SIN(alo)
  662. RETURN
  663. END SUBROUTINE llij_ps
  664. SUBROUTINE ijll_ps(i, j, proj, lat, lon)
  665. ! This is the inverse subroutine of llij_ps. It returns the
  666. ! latitude and longitude of an i/j point given the projection info
  667. ! structure.
  668. IMPLICIT NONE
  669. ! Declare input arguments
  670. REAL, INTENT(IN) :: i ! Column
  671. REAL, INTENT(IN) :: j ! Row
  672. TYPE (proj_info), INTENT(IN) :: proj
  673. ! Declare output arguments
  674. REAL, INTENT(OUT) :: lat ! -90 -> 90 north
  675. REAL, INTENT(OUT) :: lon ! -180 -> 180 East
  676. ! Local variables
  677. REAL :: reflon
  678. REAL :: scale_top
  679. REAL :: xx,yy
  680. REAL :: gi2, r2
  681. REAL :: arccos
  682. ! Begin Code
  683. ! Compute the reference longitude by rotating 90 degrees to the east
  684. ! to find the longitude line parallel to the positive x-axis.
  685. reflon = proj%stdlon + 90.
  686. ! Compute numerator term of map scale factor
  687. scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
  688. ! Compute radius to point of interest
  689. xx = i - proj%polei
  690. yy = (j - proj%polej) * proj%hemi
  691. r2 = xx**2 + yy**2
  692. ! Now the magic code
  693. IF (r2 .EQ. 0.) THEN
  694. lat = proj%hemi * 90.
  695. lon = reflon
  696. ELSE
  697. gi2 = (proj%rebydx * scale_top)**2.
  698. lat = deg_per_rad * proj%hemi * ASIN((gi2-r2)/(gi2+r2))
  699. arccos = ACOS(xx/SQRT(r2))
  700. IF (yy .GT. 0) THEN
  701. lon = reflon + deg_per_rad * arccos
  702. ELSE
  703. lon = reflon - deg_per_rad * arccos
  704. ENDIF
  705. ENDIF
  706. ! Convert to a -180 -> 180 East convention
  707. IF (lon .GT. 180.) lon = lon - 360.
  708. IF (lon .LT. -180.) lon = lon + 360.
  709. RETURN
  710. END SUBROUTINE ijll_ps
  711. SUBROUTINE set_ps_wgs84(proj)
  712. ! Initializes a polar-stereographic map projection (WGS84 ellipsoid)
  713. ! from the partially filled proj structure. This routine computes the
  714. ! radius to the southwest corner and computes the i/j location of the
  715. ! pole for use in llij_ps and ijll_ps.
  716. IMPLICIT NONE
  717. ! Arguments
  718. TYPE(proj_info), INTENT(INOUT) :: proj
  719. ! Local variables
  720. real :: h, mc, tc, t, rho
  721. h = proj%hemi
  722. mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
  723. tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg)))* &
  724. (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
  725. ! Find the i/j location of reference lat/lon with respect to the pole of the projection
  726. t = sqrt(((1.0-sin(h*proj%lat1*rad_per_deg))/(1.0+sin(h*proj%lat1*rad_per_deg)))* &
  727. (((1.0+E_WGS84*sin(h*proj%lat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%lat1*rad_per_deg)) )**E_WGS84 ) )
  728. rho = h * (A_WGS84 / proj%dx) * mc * t / tc
  729. proj%polei = rho * sin((h*proj%lon1 - h*proj%stdlon)*rad_per_deg)
  730. proj%polej = -rho * cos((h*proj%lon1 - h*proj%stdlon)*rad_per_deg)
  731. RETURN
  732. END SUBROUTINE set_ps_wgs84
  733. SUBROUTINE llij_ps_wgs84(lat,lon,proj,i,j)
  734. ! Given latitude (-90 to 90), longitude (-180 to 180), and the
  735. ! standard polar-stereographic projection information via the
  736. ! public proj structure, this routine returns the i/j indices which
  737. ! if within the domain range from 1->nx and 1->ny, respectively.
  738. IMPLICIT NONE
  739. ! Arguments
  740. REAL, INTENT(IN) :: lat
  741. REAL, INTENT(IN) :: lon
  742. REAL, INTENT(OUT) :: i !(x-index)
  743. REAL, INTENT(OUT) :: j !(y-index)
  744. TYPE(proj_info),INTENT(IN) :: proj
  745. ! Local variables
  746. real :: h, mc, tc, t, rho
  747. h = proj%hemi
  748. mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
  749. tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg)))* &
  750. (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
  751. t = sqrt(((1.0-sin(h*lat*rad_per_deg))/(1.0+sin(h*lat*rad_per_deg))) * &
  752. (((1.0+E_WGS84*sin(h*lat*rad_per_deg))/(1.0-E_WGS84*sin(h*lat*rad_per_deg)))**E_WGS84))
  753. ! Find the x/y location of the requested lat/lon with respect to the pole of the projection
  754. rho = (A_WGS84 / proj%dx) * mc * t / tc
  755. i = h * rho * sin((h*lon - h*proj%stdlon)*rad_per_deg)
  756. j = h *(-rho)* cos((h*lon - h*proj%stdlon)*rad_per_deg)
  757. ! Get i/j relative to reference i/j
  758. i = proj%knowni + (i - proj%polei)
  759. j = proj%knownj + (j - proj%polej)
  760. RETURN
  761. END SUBROUTINE llij_ps_wgs84
  762. SUBROUTINE ijll_ps_wgs84(i, j, proj, lat, lon)
  763. ! This is the inverse subroutine of llij_ps. It returns the
  764. ! latitude and longitude of an i/j point given the projection info
  765. ! structure.
  766. implicit none
  767. ! Arguments
  768. REAL, INTENT(IN) :: i ! Column
  769. REAL, INTENT(IN) :: j ! Row
  770. REAL, INTENT(OUT) :: lat ! -90 -> 90 north
  771. REAL, INTENT(OUT) :: lon ! -180 -> 180 East
  772. TYPE (proj_info), INTENT(IN) :: proj
  773. ! Local variables
  774. real :: h, mc, tc, t, rho, x, y
  775. real :: chi, a, b, c, d
  776. h = proj%hemi
  777. x = (i - proj%knowni + proj%polei)
  778. y = (j - proj%knownj + proj%polej)
  779. mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
  780. tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg))) * &
  781. (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
  782. rho = sqrt((x*proj%dx)**2.0 + (y*proj%dx)**2.0)
  783. t = rho * tc / (A_WGS84 * mc)
  784. lon = h*proj%stdlon + h*atan2(h*x,h*(-y))
  785. chi = PI/2.0-2.0*atan(t)
  786. a = 1./2.*E_WGS84**2. + 5./24.*E_WGS84**4. + 1./40.*E_WGS84**6. + 73./2016.*E_WGS84**8.
  787. b = 7./24.*E_WGS84**4. + 29./120.*E_WGS84**6. + 54113./40320.*E_WGS84**8.
  788. c = 7./30.*E_WGS84**6. + 81./280.*E_WGS84**8.
  789. d = 4279./20160.*E_WGS84**8.
  790. lat = chi + sin(2.*chi)*(a + cos(2.*chi)*(b + cos(2.*chi)*(c + d*cos(2.*chi))))
  791. lat = h * lat
  792. lat = lat*deg_per_rad
  793. lon = lon*deg_per_rad
  794. RETURN
  795. END SUBROUTINE ijll_ps_wgs84
  796. SUBROUTINE set_albers_nad83(proj)
  797. ! Initializes an Albers equal area map projection (NAD83 ellipsoid)
  798. ! from the partially filled proj structure. This routine computes the
  799. ! radius to the southwest corner and computes the i/j location of the
  800. ! pole for use in llij_albers_nad83 and ijll_albers_nad83.
  801. IMPLICIT NONE
  802. ! Arguments
  803. TYPE(proj_info), INTENT(INOUT) :: proj
  804. ! Local variables
  805. real :: h, m1, m2, q1, q2, theta, q, sinphi
  806. h = proj%hemi
  807. m1 = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_NAD83*sin(h*proj%truelat1*rad_per_deg))**2.0)
  808. m2 = cos(h*proj%truelat2*rad_per_deg)/sqrt(1.0-(E_NAD83*sin(h*proj%truelat2*rad_per_deg))**2.0)
  809. sinphi = sin(proj%truelat1*rad_per_deg)
  810. q1 = (1.0-E_NAD83**2.0) * &
  811. ((sinphi/(1.0-(E_NAD83*sinphi)**2.0)) - 1.0/(2.0*E_NAD83) * log((1.0-E_NAD83*sinphi)/(1.0+E_NAD83*sinphi)))
  812. sinphi = sin(proj%truelat2*rad_per_deg)
  813. q2 = (1.0-E_NAD83**2.0) * &
  814. ((sinphi/(1.0-(E_NAD83*sinphi)**2.0)) - 1.0/(2.0*E_NAD83) * log((1.0-E_NAD83*sinphi)/(1.0+E_NAD83*sinphi)))
  815. if (proj%truelat1 == proj%truelat2) then
  816. proj%nc = sin(proj%truelat1*rad_per_deg)
  817. else
  818. proj%nc = (m1**2.0 - m2**2.0) / (q2 - q1)
  819. end if
  820. proj%bigc = m1**2.0 + proj%nc*q1
  821. ! Find the i/j location of reference lat/lon with respect to the pole of the projection
  822. sinphi = sin(proj%lat1*rad_per_deg)
  823. q = (1.0-E_NAD83**2.0) * &
  824. ((sinphi/(1.0-(E_NAD83*sinphi)**2.0)) - 1.0/(2.0*E_NAD83) * log((1.0-E_NAD83*sinphi)/(1.0+E_NAD83*sinphi)))
  825. proj%rho0 = h * (A_NAD83 / proj%dx) * sqrt(proj%bigc - proj%nc * q) / proj%nc
  826. theta = proj%nc*(proj%lon1 - proj%stdlon)*rad_per_deg
  827. proj%polei = proj%rho0 * sin(h*theta)
  828. proj%polej = proj%rho0 - proj%rho0 * cos(h*theta)
  829. RETURN
  830. END SUBROUTINE set_albers_nad83
  831. SUBROUTINE llij_albers_nad83(lat,lon,proj,i,j)
  832. ! Given latitude (-90 to 90), longitude (-180 to 180), and the
  833. ! standard projection information via the
  834. ! public proj structure, this routine returns the i/j indices which
  835. ! if within the domain range from 1->nx and 1->ny, respectively.
  836. IMPLICIT NONE
  837. ! Arguments
  838. REAL, INTENT(IN) :: lat
  839. REAL, INTENT(IN) :: lon
  840. REAL, INTENT(OUT) :: i !(x-index)
  841. REAL, INTENT(OUT) :: j !(y-index)
  842. TYPE(proj_info),INTENT(IN) :: proj
  843. ! Local variables
  844. real :: h, q, rho, theta, sinphi
  845. h = proj%hemi
  846. sinphi = sin(h*lat*rad_per_deg)
  847. ! Find the x/y location of the requested lat/lon with respect to the pole of the projection
  848. q = (1.0-E_NAD83**2.0) * &
  849. ((sinphi/(1.0-(E_NAD83*sinphi)**2.0)) - 1.0/(2.0*E_NAD83) * log((1.0-E_NAD83*sinphi)/(1.0+E_NAD83*sinphi)))
  850. rho = h * (A_NAD83 / proj%dx) * sqrt(proj%bigc - proj%nc * q) / proj%nc
  851. theta = proj%nc * (h*lon - h*proj%stdlon)*rad_per_deg
  852. i = h*rho*sin(theta)
  853. j = h*proj%rho0 - h*rho*cos(theta)
  854. ! Get i/j relative to reference i/j
  855. i = proj%knowni + (i - proj%polei)
  856. j = proj%knownj + (j - proj%polej)
  857. RETURN
  858. END SUBROUTINE llij_albers_nad83
  859. SUBROUTINE ijll_albers_nad83(i, j, proj, lat, lon)
  860. ! This is the inverse subroutine of llij_albers_nad83. It returns the
  861. ! latitude and longitude of an i/j point given the projection info
  862. ! structure.
  863. implicit none
  864. ! Arguments
  865. REAL, INTENT(IN) :: i ! Column
  866. REAL, INTENT(IN) :: j ! Row
  867. REAL, INTENT(OUT) :: lat ! -90 -> 90 north
  868. REAL, INTENT(OUT) :: lon ! -180 -> 180 East
  869. TYPE (proj_info), INTENT(IN) :: proj
  870. ! Local variables
  871. real :: h, q, rho, theta, beta, x, y
  872. real :: a, b, c
  873. h = proj%hemi
  874. x = (i - proj%knowni + proj%polei)
  875. y = (j - proj%knownj + proj%polej)
  876. rho = sqrt(x**2.0 + (proj%rho0 - y)**2.0)
  877. theta = atan2(x, proj%rho0-y)
  878. q = (proj%bigc - (rho*proj%nc*proj%dx/A_NAD83)**2.0) / proj%nc
  879. beta = asin(q/(1.0 - log((1.0-E_NAD83)/(1.0+E_NAD83))*(1.0-E_NAD83**2.0)/(2.0*E_NAD83)))
  880. a = 1./3.*E_NAD83**2. + 31./180.*E_NAD83**4. + 517./5040.*E_NAD83**6.
  881. b = 23./360.*E_NAD83**4. + 251./3780.*E_NAD83**6.
  882. c = 761./45360.*E_NAD83**6.
  883. lat = beta + a*sin(2.*beta) + b*sin(4.*beta) + c*sin(6.*beta)
  884. lat = h*lat*deg_per_rad
  885. lon = proj%stdlon + theta*deg_per_rad/proj%nc
  886. RETURN
  887. END SUBROUTINE ijll_albers_nad83
  888. SUBROUTINE set_lc(proj)
  889. ! Initialize the remaining items in the proj structure for a
  890. ! lambert conformal grid.
  891. IMPLICIT NONE
  892. TYPE(proj_info), INTENT(INOUT) :: proj
  893. REAL :: arg
  894. REAL :: deltalon1
  895. REAL :: tl1r
  896. REAL :: ctl1r
  897. ! Compute cone factor
  898. CALL lc_cone(proj%truelat1, proj%truelat2, proj%cone)
  899. ! Compute longitude differences and ensure we stay out of the
  900. ! forbidden "cut zone"
  901. deltalon1 = proj%lon1 - proj%stdlon
  902. IF (deltalon1 .GT. +180.) deltalon1 = deltalon1 - 360.
  903. IF (deltalon1 .LT. -180.) deltalon1 = deltalon1 + 360.
  904. ! Convert truelat1 to radian and compute COS for later use
  905. tl1r = proj%truelat1 * rad_per_deg
  906. ctl1r = COS(tl1r)
  907. ! Compute the radius to our known lower-left (SW) corner
  908. proj%rsw = proj%rebydx * ctl1r/proj%cone * &
  909. (TAN((90.*proj%hemi-proj%lat1)*rad_per_deg/2.) / &
  910. TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone
  911. ! Find pole point
  912. arg = proj%cone*(deltalon1*rad_per_deg)
  913. proj%polei = proj%hemi*proj%knowni - proj%hemi * proj%rsw * SIN(arg)
  914. proj%polej = proj%hemi*proj%knownj + proj%rsw * COS(arg)
  915. RETURN
  916. END SUBROUTINE set_lc
  917. SUBROUTINE lc_cone(truelat1, truelat2, cone)
  918. ! Subroutine to compute the cone factor of a Lambert Conformal projection
  919. IMPLICIT NONE
  920. ! Input Args
  921. REAL, INTENT(IN) :: truelat1 ! (-90 -> 90 degrees N)
  922. REAL, INTENT(IN) :: truelat2 ! " " " " "
  923. ! Output Args
  924. REAL, INTENT(OUT) :: cone
  925. ! Locals
  926. ! BEGIN CODE
  927. ! First, see if this is a secant or tangent projection. For tangent
  928. ! projections, truelat1 = truelat2 and the cone is tangent to the
  929. ! Earth's surface at this latitude. For secant projections, the cone
  930. ! intersects the Earth's surface at each of the distinctly different
  931. ! latitudes
  932. IF (ABS(truelat1-truelat2) .GT. 0.1) THEN
  933. cone = ALOG10(COS(truelat1*rad_per_deg)) - &
  934. ALOG10(COS(truelat2*rad_per_deg))
  935. cone = cone /(ALOG10(TAN((45.0 - ABS(truelat1)/2.0) * rad_per_deg)) - &
  936. ALOG10(TAN((45.0 - ABS(truelat2)/2.0) * rad_per_deg)))
  937. ELSE
  938. cone = SIN(ABS(truelat1)*rad_per_deg )
  939. ENDIF
  940. RETURN
  941. END SUBROUTINE lc_cone
  942. SUBROUTINE ijll_lc( i, j, proj, lat, lon)
  943. ! Subroutine to convert from the (i,j) cartesian coordinate to the
  944. ! geographical latitude and longitude for a Lambert Conformal projection.
  945. ! History:
  946. ! 25 Jul 01: Corrected by B. Shaw, NOAA/FSL
  947. !
  948. IMPLICIT NONE
  949. ! Input Args
  950. REAL, INTENT(IN) :: i ! Cartesian X coordinate
  951. REAL, INTENT(IN) :: j ! Cartesian Y coordinate
  952. TYPE(proj_info),INTENT(IN) :: proj ! Projection info structure
  953. ! Output Args
  954. REAL, INTENT(OUT) :: lat ! Latitude (-90->90 deg N)
  955. REAL, INTENT(OUT) :: lon ! Longitude (-180->180 E)
  956. ! Locals
  957. REAL :: inew
  958. REAL :: jnew
  959. REAL :: r
  960. REAL :: chi,chi1,chi2
  961. REAL :: r2
  962. REAL :: xx
  963. REAL :: yy
  964. ! BEGIN CODE
  965. chi1 = (90. - proj%hemi*proj%truelat1)*rad_per_deg
  966. chi2 = (90. - proj%hemi*proj%truelat2)*rad_per_deg
  967. ! See if we are in the southern hemispere and flip the indices
  968. ! if we are.
  969. inew = proj%hemi * i
  970. jnew = proj%hemi * j
  971. ! Compute radius**2 to i/j location
  972. xx = inew - proj%polei
  973. yy = proj%polej - jnew
  974. r2 = (xx*xx + yy*yy)
  975. r = SQRT(r2)/proj%rebydx
  976. ! Convert to lat/lon
  977. IF (r2 .EQ. 0.) THEN
  978. lat = proj%hemi * 90.
  979. lon = proj%stdlon
  980. ELSE
  981. ! Longitude
  982. lon = proj%stdlon + deg_per_rad * ATAN2(proj%hemi*xx,yy)/proj%cone
  983. lon = AMOD(lon+360., 360.)
  984. ! Latitude. Latitude determined by solving an equation adapted
  985. ! from:
  986. ! Maling, D.H., 1973: Coordinate Systems and Map Projections
  987. ! Equations #20 in Appendix I.
  988. IF (chi1 .EQ. chi2) THEN
  989. chi = 2.0*ATAN( ( r/TAN(chi1) )**(1./proj%cone) * TAN(chi1*0.5) )
  990. ELSE
  991. chi = 2.0*ATAN( (r*proj%cone/SIN(chi1))**(1./proj%cone) * TAN(chi1*0.5))
  992. ENDIF
  993. lat = (90.0-chi*deg_per_rad)*proj%hemi
  994. ENDIF
  995. IF (lon .GT. +180.) lon = lon - 360.
  996. IF (lon .LT. -180.) lon = lon + 360.
  997. RETURN
  998. END SUBROUTINE ijll_lc
  999. SUBROUTINE llij_lc( lat, lon, proj, i, j)
  1000. ! Subroutine to compute the geographical latitude and longitude values
  1001. ! to the cartesian x/y on a Lambert Conformal projection.
  1002. IMPLICIT NONE
  1003. ! Input Args
  1004. REAL, INTENT(IN) :: lat ! Latitude (-90->90 deg N)
  1005. REAL, INTENT(IN) :: lon ! Longitude (-180->180 E)
  1006. TYPE(proj_info),INTENT(IN) :: proj ! Projection info structure
  1007. ! Output Args
  1008. REAL, INTENT(OUT) :: i ! Cartesian X coordinate
  1009. REAL, INTENT(OUT) :: j ! Cartesian Y coordinate
  1010. ! Locals
  1011. REAL :: arg
  1012. REAL :: deltalon
  1013. REAL :: tl1r
  1014. REAL :: rm
  1015. REAL :: ctl1r
  1016. ! BEGIN CODE
  1017. ! Compute deltalon between known longitude and standard lon and ensure
  1018. ! it is not in the cut zone
  1019. deltalon = lon - proj%stdlon
  1020. IF (deltalon .GT. +180.) deltalon = deltalon - 360.
  1021. IF (deltalon .LT. -180.) deltalon = deltalon + 360.
  1022. ! Convert truelat1 to radian and compute COS for later use
  1023. tl1r = proj%truelat1 * rad_per_deg
  1024. ctl1r = COS(tl1r)
  1025. ! Radius to desired point
  1026. rm = proj%rebydx * ctl1r/proj%cone * &
  1027. (TAN((90.*proj%hemi-lat)*rad_per_deg/2.) / &
  1028. TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone
  1029. arg = proj%cone*(deltalon*rad_per_deg)
  1030. i = proj%polei + proj%hemi * rm * SIN(arg)
  1031. j = proj%polej - rm * COS(arg)
  1032. ! Finally, if we are in the southern hemisphere, flip the i/j
  1033. ! values to a coordinate system where (1,1) is the SW corner
  1034. ! (what we assume) which is different than the original NCEP
  1035. ! algorithms which used the NE corner as the origin in the
  1036. ! southern hemisphere (left-hand vs. right-hand coordinate?)
  1037. i = proj%hemi * i
  1038. j = proj%hemi * j
  1039. RETURN
  1040. END SUBROUTINE llij_lc
  1041. SUBROUTINE set_merc(proj)
  1042. ! Sets up the remaining basic elements for the mercator projection
  1043. IMPLICIT NONE
  1044. TYPE(proj_info), INTENT(INOUT) :: proj
  1045. REAL :: clain
  1046. ! Preliminary variables
  1047. clain = COS(rad_per_deg*proj%truelat1)
  1048. proj%dlon = proj%dx / (proj%re_m * clain)
  1049. ! Compute distance from equator to origin, and store in the
  1050. ! proj%rsw tag.
  1051. proj%rsw = 0.
  1052. IF (proj%lat1 .NE. 0.) THEN
  1053. proj%rsw = (ALOG(TAN(0.5*((proj%lat1+90.)*rad_per_deg))))/proj%dlon
  1054. ENDIF
  1055. RETURN
  1056. END SUBROUTINE set_merc
  1057. SUBROUTINE llij_merc(lat, lon, proj, i, j)
  1058. ! Compute i/j coordinate from lat lon for mercator projection
  1059. IMPLICIT NONE
  1060. REAL, INTENT(IN)

Large files files are truncated, but you can click here to view the full file