3 ! Module that defines constants, data structures, and
4 ! subroutines used to convert grid indices to lat/lon
7 ! SUPPORTED PROJECTIONS
8 ! ---------------------
9 ! Cylindrical Lat/Lon (code = PROJ_LATLON)
10 ! Mercator (code = PROJ_MERC)
11 ! Lambert Conformal (code = PROJ_LC)
12 ! Gaussian (code = PROJ_GAUSS)
13 ! Polar Stereographic (code = PROJ_PS)
14 ! Rotated Lat/Lon (code = PROJ_ROTLL)
18 ! The routines contained within were adapted from routines
19 ! obtained from NCEP's w3 library. The original NCEP routines were less
20 ! flexible (e.g., polar-stereo routines only supported truelat of 60N/60S)
21 ! than what we needed, so modifications based on equations in Hoke, Hayes, and
22 ! Renninger (AFGWC/TN/79-003) were added to improve the flexibility.
23 ! Additionally, coding was improved to F90 standards and the routines were
24 ! combined into this module.
29 ! For mercator, lambert conformal, and polar-stereographic projections,
30 ! the routines within assume the following:
32 ! 1. Grid is dimensioned (i,j) where i is the East-West direction,
33 ! positive toward the east, and j is the north-south direction,
34 ! positive toward the north.
35 ! 2. Origin is at (1,1) and is located at the southwest corner,
36 ! regardless of hemispere.
37 ! 3. Grid spacing (dx) is always positive.
38 ! 4. Values of true latitudes must be positive for NH domains
39 ! and negative for SH domains.
41 ! For the latlon and Gaussian projection, the grid origin may be at any
42 ! of the corners, and the deltalat and deltalon values can be signed to
43 ! account for this using the following convention:
44 ! Origin Location Deltalat Sign Deltalon Sign
45 ! --------------- ------------- -------------
52 ! 1. Any arguments that are a latitude value are expressed in
53 ! degrees north with a valid range of -90 -> 90
54 ! 2. Any arguments that are a longitude value are expressed in
55 ! degrees east with a valid range of -180 -> 180.
56 ! 3. Distances are in meters and are always positive.
57 ! 4. The standard longitude (stdlon) is defined as the longitude
58 ! line which is parallel to the grid's y-axis (j-direction), along
59 ! which latitude increases (NOT the absolute value of latitude, but
60 ! the actual latitude, such that latitude increases continuously
61 ! from the south pole to the north pole) as j increases.
62 ! 5. One true latitude value is required for polar-stereographic and
63 ! mercator projections, and defines at which latitude the
64 ! grid spacing is true. For lambert conformal, two true latitude
65 ! values must be specified, but may be set equal to each other to
66 ! specify a tangent projection instead of a secant projection.
70 ! To use the routines in this module, the calling routines must have the
71 ! following statement at the beginning of its declaration block:
74 ! The use of the module not only provides access to the necessary routines,
75 ! but also defines a structure of TYPE (proj_info) that can be used
76 ! to declare a variable of the same type to hold your map projection
77 ! information. It also defines some integer parameters that contain
78 ! the projection codes so one only has to use those variable names rather
79 ! than remembering the acutal code when using them. The basic steps are
82 ! 1. Ensure the "USE map_utils" is in your declarations.
83 ! 2. Declare the projection information structure as type(proj_info):
84 ! TYPE(proj_info) :: proj
85 ! 3. Populate your structure by calling the map_set routine:
86 ! CALL map_set(code,lat1,lon1,knowni,knownj,dx,stdlon,truelat1,truelat2,proj)
88 ! code (input) = one of PROJ_LATLON, PROJ_MERC, PROJ_LC, PROJ_PS,
89 ! PROJ_GAUSS, or PROJ_ROTLL
90 ! lat1 (input) = Latitude of grid origin point (i,j)=(1,1)
92 ! lon1 (input) = Longitude of grid origin
93 ! knowni (input) = origin point, x-location
94 ! knownj (input) = origin point, y-location
95 ! dx (input) = grid spacing in meters (ignored for LATLON projections)
96 ! stdlon (input) = Standard longitude for PROJ_PS and PROJ_LC,
97 ! deltalon (see assumptions) for PROJ_LATLON,
98 ! ignored for PROJ_MERC
99 ! truelat1 (input) = 1st true latitude for PROJ_PS, PROJ_LC, and
100 ! PROJ_MERC, deltalat (see assumptions) for PROJ_LATLON
101 ! truelat2 (input) = 2nd true latitude for PROJ_LC,
102 ! ignored for all others.
103 ! proj (output) = The structure of type (proj_info) that will be fully
104 ! populated after this call
106 ! 4. Now that the proj structure is populated, you may call either
107 ! of the following routines:
109 ! latlon_to_ij(proj, lat, lon, i, j)
110 ! ij_to_latlon(proj, i, j, lat, lon)
112 ! It is incumbent upon the calling routine to determine whether or
113 ! not the values returned are within your domain's bounds. All values
114 ! of i, j, lat, and lon are REAL values.
119 ! Hoke, Hayes, and Renninger, "Map Preojections and Grid Systems for
120 ! Meteorological Applications." AFGWC/TN-79/003(Rev), Air Weather
123 ! NCAR MM5v3 Modeling System, REGRIDDER program, module_first_guess_map.F
124 ! NCEP routines w3fb06, w3fb07, w3fb08, w3fb09, w3fb11, w3fb12
128 ! 27 Mar 2001 - Original Version
129 ! Brent L. Shaw, NOAA/FSL (CSU/CIRA)
131 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
135 INTEGER, PARAMETER :: HH=4, VV=5
137 REAL, PARAMETER :: PI = 3.141592653589793
138 REAL, PARAMETER :: OMEGA_E = 7.292e-5
140 REAL, PARAMETER :: DEG_PER_RAD = 180./PI
141 REAL, PARAMETER :: RAD_PER_DEG = PI/180.
143 REAL, PARAMETER :: A_WGS84 = 6378137.
144 REAL, PARAMETER :: B_WGS84 = 6356752.314
145 REAL, PARAMETER :: RE_WGS84 = A_WGS84
146 REAL, PARAMETER :: E_WGS84 = 0.081819192
148 REAL, PARAMETER :: A_NAD83 = 6378137.
149 REAL, PARAMETER :: RE_NAD83 = A_NAD83
150 REAL, PARAMETER :: E_NAD83 = 0.0818187034
152 REAL, PARAMETER :: EARTH_RADIUS_M = 6370000.
153 REAL, PARAMETER :: EARTH_CIRC_M = 2.*PI*EARTH_RADIUS_M
155 INTEGER, PUBLIC, PARAMETER :: PROJ_LATLON = 0
156 INTEGER, PUBLIC, PARAMETER :: PROJ_LC = 1
157 INTEGER, PUBLIC, PARAMETER :: PROJ_PS = 2
158 INTEGER, PUBLIC, PARAMETER :: PROJ_PS_WGS84 = 102
159 INTEGER, PUBLIC, PARAMETER :: PROJ_MERC = 3
160 INTEGER, PUBLIC, PARAMETER :: PROJ_GAUSS = 4
161 INTEGER, PUBLIC, PARAMETER :: PROJ_CYL = 5
162 INTEGER, PUBLIC, PARAMETER :: PROJ_CASSINI = 6
163 INTEGER, PUBLIC, PARAMETER :: PROJ_ALBERS_NAD83 = 105
164 INTEGER, PUBLIC, PARAMETER :: PROJ_ROTLL = 203
166 ! Define some private constants
167 INTEGER, PRIVATE, PARAMETER :: HIGH = 8
171 INTEGER :: code ! Integer code for projection TYPE
172 INTEGER :: nlat ! For Gaussian -- number of latitude points
173 ! north of the equator
176 INTEGER :: ixdim ! For Rotated Lat/Lon -- number of mass points
178 INTEGER :: jydim ! For Rotated Lat/Lon -- number of rows
179 INTEGER :: stagger ! For Rotated Lat/Lon -- mass or velocity grid
180 REAL :: phi ! For Rotated Lat/Lon -- domain half-extent in
182 REAL :: lambda ! For Rotated Lat/Lon -- domain half-extend in
184 REAL :: lat1 ! SW latitude (1,1) in degrees (-90->90N)
185 REAL :: lon1 ! SW longitude (1,1) in degrees (-180->180E)
186 REAL :: lat0 ! For Cassini, latitude of projection pole
187 REAL :: lon0 ! For Cassini, longitude of projection pole
188 REAL :: dx ! Grid spacing in meters at truelats, used
189 ! only for ps, lc, and merc projections
190 REAL :: dy ! Grid spacing in meters at truelats, used
191 ! only for ps, lc, and merc projections
192 REAL :: latinc ! Latitude increment for cylindrical lat/lon
193 REAL :: loninc ! Longitude increment for cylindrical lat/lon
194 ! also the lon increment for Gaussian grid
195 REAL :: dlat ! Lat increment for lat/lon grids
196 REAL :: dlon ! Lon increment for lat/lon grids
197 REAL :: stdlon ! Longitude parallel to y-axis (-180->180E)
198 REAL :: truelat1 ! First true latitude (all projections)
199 REAL :: truelat2 ! Second true lat (LC only)
200 REAL :: hemi ! 1 for NH, -1 for SH
201 REAL :: cone ! Cone factor for LC projections
202 REAL :: polei ! Computed i-location of pole point
203 REAL :: polej ! Computed j-location of pole point
204 REAL :: rsw ! Computed radius to SW corner
205 REAL :: rebydx ! Earth radius divided by dx
206 REAL :: knowni ! X-location of known lat/lon
207 REAL :: knownj ! Y-location of known lat/lon
208 REAL :: re_m ! Radius of spherical earth, meters
209 REAL :: rho0 ! For Albers equal area
210 REAL :: nc ! For Albers equal area
211 REAL :: bigc ! For Albers equal area
212 LOGICAL :: init ! Flag to indicate if this struct is
214 LOGICAL :: wrap ! For Gaussian -- flag to indicate wrapping
216 REAL, POINTER, DIMENSION(:) :: gauss_lat ! Latitude array for Gaussian grid
220 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
222 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
224 SUBROUTINE map_init(proj)
225 ! Initializes the map projection structure to missing values
228 TYPE(proj_info), INTENT(INOUT) :: proj
240 proj%truelat1 = -999.9
241 proj%truelat2 = -999.9
256 proj%re_m = EARTH_RADIUS_M
262 nullify(proj%gauss_lat)
264 END SUBROUTINE map_init
267 SUBROUTINE map_set(proj_code, proj, lat1, lon1, lat0, lon0, knowni, knownj, dx, latinc, &
268 loninc, stdlon, truelat1, truelat2, nlat, nlon, ixdim, jydim, &
269 stagger, phi, lambda, r_earth)
270 ! Given a partially filled proj_info structure, this routine computes
271 ! polei, polej, rsw, and cone (if LC projection) to complete the
272 ! structure. This allows us to eliminate redundant calculations when
273 ! calling the coordinate conversion routines multiple times for the
275 ! This will generally be the first routine called when a user wants
276 ! to be able to use the coordinate conversion routines, and it
277 ! will call the appropriate subroutines based on the
278 ! proj%code which indicates which projection type this is.
283 INTEGER, INTENT(IN) :: proj_code
284 INTEGER, INTENT(IN), OPTIONAL :: nlat
285 INTEGER, INTENT(IN), OPTIONAL :: nlon
286 INTEGER, INTENT(IN), OPTIONAL :: ixdim
287 INTEGER, INTENT(IN), OPTIONAL :: jydim
288 INTEGER, INTENT(IN), OPTIONAL :: stagger
289 REAL, INTENT(IN), OPTIONAL :: latinc
290 REAL, INTENT(IN), OPTIONAL :: loninc
291 REAL, INTENT(IN), OPTIONAL :: lat1
292 REAL, INTENT(IN), OPTIONAL :: lon1
293 REAL, INTENT(IN), OPTIONAL :: lat0
294 REAL, INTENT(IN), OPTIONAL :: lon0
295 REAL, INTENT(IN), OPTIONAL :: dx
296 REAL, INTENT(IN), OPTIONAL :: stdlon
297 REAL, INTENT(IN), OPTIONAL :: truelat1
298 REAL, INTENT(IN), OPTIONAL :: truelat2
299 REAL, INTENT(IN), OPTIONAL :: knowni
300 REAL, INTENT(IN), OPTIONAL :: knownj
301 REAL, INTENT(IN), OPTIONAL :: phi
302 REAL, INTENT(IN), OPTIONAL :: lambda
303 REAL, INTENT(IN), OPTIONAL :: r_earth
304 TYPE(proj_info), INTENT(OUT) :: proj
311 ! First, verify that mandatory parameters are present for the specified proj_code
312 IF ( proj_code == PROJ_LC ) THEN
313 IF ( .NOT.PRESENT(truelat1) .OR. &
314 .NOT.PRESENT(truelat2) .OR. &
315 .NOT.PRESENT(lat1) .OR. &
316 .NOT.PRESENT(lon1) .OR. &
317 .NOT.PRESENT(knowni) .OR. &
318 .NOT.PRESENT(knownj) .OR. &
319 .NOT.PRESENT(stdlon) .OR. &
320 .NOT.PRESENT(dx) ) THEN
321 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
322 PRINT '(A)', ' truelat1, truelat2, lat1, lon1, knowni, knownj, stdlon, dx'
323 CALL wrf_error_fatal ( 'MAP_INIT' )
325 ELSE IF ( proj_code == PROJ_PS ) THEN
326 IF ( .NOT.PRESENT(truelat1) .OR. &
327 .NOT.PRESENT(lat1) .OR. &
328 .NOT.PRESENT(lon1) .OR. &
329 .NOT.PRESENT(knowni) .OR. &
330 .NOT.PRESENT(knownj) .OR. &
331 .NOT.PRESENT(stdlon) .OR. &
332 .NOT.PRESENT(dx) ) THEN
333 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
334 PRINT '(A)', ' truelat1, lat1, lon1, knonwi, knownj, stdlon, dx'
335 CALL wrf_error_fatal ( 'MAP_INIT' )
337 ELSE IF ( proj_code == PROJ_PS_WGS84 ) THEN
338 IF ( .NOT.PRESENT(truelat1) .OR. &
339 .NOT.PRESENT(lat1) .OR. &
340 .NOT.PRESENT(lon1) .OR. &
341 .NOT.PRESENT(knowni) .OR. &
342 .NOT.PRESENT(knownj) .OR. &
343 .NOT.PRESENT(stdlon) .OR. &
344 .NOT.PRESENT(dx) ) THEN
345 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
346 PRINT '(A)', ' truelat1, lat1, lon1, knonwi, knownj, stdlon, dx'
347 CALL wrf_error_fatal ( 'MAP_INIT' )
349 ELSE IF ( proj_code == PROJ_ALBERS_NAD83 ) THEN
350 IF ( .NOT.PRESENT(truelat1) .OR. &
351 .NOT.PRESENT(truelat2) .OR. &
352 .NOT.PRESENT(lat1) .OR. &
353 .NOT.PRESENT(lon1) .OR. &
354 .NOT.PRESENT(knowni) .OR. &
355 .NOT.PRESENT(knownj) .OR. &
356 .NOT.PRESENT(stdlon) .OR. &
357 .NOT.PRESENT(dx) ) THEN
358 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
359 PRINT '(A)', ' truelat1, truelat2, lat1, lon1, knonwi, knownj, stdlon, dx'
360 CALL wrf_error_fatal ( 'MAP_INIT' )
362 ELSE IF ( proj_code == PROJ_MERC ) THEN
363 IF ( .NOT.PRESENT(truelat1) .OR. &
364 .NOT.PRESENT(lat1) .OR. &
365 .NOT.PRESENT(lon1) .OR. &
366 .NOT.PRESENT(knowni) .OR. &
367 .NOT.PRESENT(knownj) .OR. &
368 .NOT.PRESENT(dx) ) THEN
369 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
370 PRINT '(A)', ' truelat1, lat1, lon1, knowni, knownj, dx'
371 CALL wrf_error_fatal ( 'MAP_INIT' )
373 ELSE IF ( proj_code == PROJ_LATLON ) THEN
374 IF ( .NOT.PRESENT(latinc) .OR. &
375 .NOT.PRESENT(loninc) .OR. &
376 .NOT.PRESENT(knowni) .OR. &
377 .NOT.PRESENT(knownj) .OR. &
378 .NOT.PRESENT(lat1) .OR. &
379 .NOT.PRESENT(lon1) ) THEN
380 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
381 PRINT '(A)', ' latinc, loninc, knowni, knownj, lat1, lon1'
382 CALL wrf_error_fatal ( 'MAP_INIT' )
384 ELSE IF ( proj_code == PROJ_CYL ) THEN
385 IF ( .NOT.PRESENT(latinc) .OR. &
386 .NOT.PRESENT(loninc) .OR. &
387 .NOT.PRESENT(stdlon) ) THEN
388 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
389 PRINT '(A)', ' latinc, loninc, stdlon'
390 CALL wrf_error_fatal ( 'MAP_INIT' )
392 ELSE IF ( proj_code == PROJ_CASSINI ) THEN
393 IF ( .NOT.PRESENT(latinc) .OR. &
394 .NOT.PRESENT(loninc) .OR. &
395 .NOT.PRESENT(lat1) .OR. &
396 .NOT.PRESENT(lon1) .OR. &
397 .NOT.PRESENT(lat0) .OR. &
398 .NOT.PRESENT(lon0) .OR. &
399 .NOT.PRESENT(knowni) .OR. &
400 .NOT.PRESENT(knownj) .OR. &
401 .NOT.PRESENT(stdlon) ) THEN
402 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
403 PRINT '(A)', ' latinc, loninc, lat1, lon1, knowni, knownj, lat0, lon0, stdlon'
404 CALL wrf_error_fatal ( 'MAP_INIT' )
406 ELSE IF ( proj_code == PROJ_GAUSS ) THEN
407 IF ( .NOT.PRESENT(nlat) .OR. &
408 .NOT.PRESENT(lat1) .OR. &
409 .NOT.PRESENT(lon1) .OR. &
410 .NOT.PRESENT(loninc) ) THEN
411 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
412 PRINT '(A)', ' nlat, lat1, lon1, loninc'
413 CALL wrf_error_fatal ( 'MAP_INIT' )
415 ELSE IF ( proj_code == PROJ_ROTLL ) THEN
416 IF ( .NOT.PRESENT(ixdim) .OR. &
417 .NOT.PRESENT(jydim) .OR. &
418 .NOT.PRESENT(phi) .OR. &
419 .NOT.PRESENT(lambda) .OR. &
420 .NOT.PRESENT(lat1) .OR. &
421 .NOT.PRESENT(lon1) .OR. &
422 .NOT.PRESENT(stagger) ) THEN
423 PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
424 PRINT '(A)', ' ixdim, jydim, phi, lambda, lat1, lon1, stagger'
425 CALL wrf_error_fatal ( 'MAP_INIT' )
428 PRINT '(A,I2)', 'Unknown projection code: ', proj_code
429 CALL wrf_error_fatal ( 'MAP_INIT' )
432 ! Check for validity of mandatory variables in proj
433 IF ( PRESENT(lat1) ) THEN
434 IF ( ABS(lat1) .GT. 90. ) THEN
435 PRINT '(A)', 'Latitude of origin corner required as follows:'
436 PRINT '(A)', ' -90N <= lat1 < = 90.N'
437 CALL wrf_error_fatal ( 'MAP_INIT' )
441 IF ( PRESENT(lon1) ) THEN
443 IF ( ABS(dummy_lon1) .GT. 180.) THEN
445 DO WHILE (ABS(dummy_lon1) > 180. .AND. iter < 10)
446 IF (dummy_lon1 < -180.) dummy_lon1 = dummy_lon1 + 360.
447 IF (dummy_lon1 > 180.) dummy_lon1 = dummy_lon1 - 360.
450 IF (abs(dummy_lon1) > 180.) THEN
451 PRINT '(A)', 'Longitude of origin required as follows:'
452 PRINT '(A)', ' -180E <= lon1 <= 180W'
453 CALL wrf_error_fatal ( 'MAP_INIT' )
458 IF ( PRESENT(lon0) ) THEN
460 IF ( ABS(dummy_lon0) .GT. 180.) THEN
462 DO WHILE (ABS(dummy_lon0) > 180. .AND. iter < 10)
463 IF (dummy_lon0 < -180.) dummy_lon0 = dummy_lon0 + 360.
464 IF (dummy_lon0 > 180.) dummy_lon0 = dummy_lon0 - 360.
467 IF (abs(dummy_lon0) > 180.) THEN
468 PRINT '(A)', 'Longitude of pole required as follows:'
469 PRINT '(A)', ' -180E <= lon0 <= 180W'
470 CALL wrf_error_fatal ( 'MAP_INIT' )
475 IF ( PRESENT(dx) ) THEN
476 IF ((dx .LE. 0.).AND.(proj_code .NE. PROJ_LATLON)) THEN
477 PRINT '(A)', 'Require grid spacing (dx) in meters be positive'
478 CALL wrf_error_fatal ( 'MAP_INIT' )
482 IF ( PRESENT(stdlon) ) THEN
483 dummy_stdlon = stdlon
484 IF ((ABS(dummy_stdlon) > 180.).AND.(proj_code /= PROJ_MERC)) THEN
486 DO WHILE (ABS(dummy_stdlon) > 180. .AND. iter < 10)
487 IF (dummy_stdlon < -180.) dummy_stdlon = dummy_stdlon + 360.
488 IF (dummy_stdlon > 180.) dummy_stdlon = dummy_stdlon - 360.
491 IF (abs(dummy_stdlon) > 180.) THEN
492 PRINT '(A)', 'Need orientation longitude (stdlon) as: '
493 PRINT '(A)', ' -180E <= stdlon <= 180W'
494 CALL wrf_error_fatal ( 'MAP_INIT' )
499 IF ( PRESENT(truelat1) ) THEN
500 IF (ABS(truelat1).GT.90.) THEN
501 PRINT '(A)', 'Set true latitude 1 for all projections'
502 CALL wrf_error_fatal ( 'MAP_INIT' )
507 proj%code = proj_code
508 IF ( PRESENT(lat1) ) proj%lat1 = lat1
509 IF ( PRESENT(lon1) ) proj%lon1 = dummy_lon1
510 IF ( PRESENT(lat0) ) proj%lat0 = lat0
511 IF ( PRESENT(lon0) ) proj%lon0 = dummy_lon0
512 IF ( PRESENT(latinc) ) proj%latinc = latinc
513 IF ( PRESENT(loninc) ) proj%loninc = loninc
514 IF ( PRESENT(knowni) ) proj%knowni = knowni
515 IF ( PRESENT(knownj) ) proj%knownj = knownj
516 IF ( PRESENT(dx) ) proj%dx = dx
517 IF ( PRESENT(stdlon) ) proj%stdlon = dummy_stdlon
518 IF ( PRESENT(truelat1) ) proj%truelat1 = truelat1
519 IF ( PRESENT(truelat2) ) proj%truelat2 = truelat2
520 IF ( PRESENT(nlat) ) proj%nlat = nlat
521 IF ( PRESENT(nlon) ) proj%nlon = nlon
522 IF ( PRESENT(ixdim) ) proj%ixdim = ixdim
523 IF ( PRESENT(jydim) ) proj%jydim = jydim
524 IF ( PRESENT(stagger) ) proj%stagger = stagger
525 IF ( PRESENT(phi) ) proj%phi = phi
526 IF ( PRESENT(lambda) ) proj%lambda = lambda
527 IF ( PRESENT(r_earth) ) proj%re_m = r_earth
529 IF ( PRESENT(dx) ) THEN
530 IF ( (proj_code == PROJ_LC) .OR. (proj_code == PROJ_PS) .OR. &
531 (proj_code == PROJ_PS_WGS84) .OR. (proj_code == PROJ_ALBERS_NAD83) .OR. &
532 (proj_code == PROJ_MERC) ) THEN
534 IF (truelat1 .LT. 0.) THEN
539 proj%rebydx = proj%re_m / dx
543 pick_proj: SELECT CASE(proj%code)
549 CALL set_ps_wgs84(proj)
551 CASE(PROJ_ALBERS_NAD83)
552 CALL set_albers_nad83(proj)
555 IF (ABS(proj%truelat2) .GT. 90.) THEN
556 proj%truelat2=proj%truelat1
572 CALL set_cassini(proj)
581 END SUBROUTINE map_set
584 SUBROUTINE latlon_to_ij(proj, lat, lon, i, j)
585 ! Converts input lat/lon values to the cartesian (i,j) value
586 ! for the given projection.
589 TYPE(proj_info), INTENT(IN) :: proj
590 REAL, INTENT(IN) :: lat
591 REAL, INTENT(IN) :: lon
592 REAL, INTENT(OUT) :: i
593 REAL, INTENT(OUT) :: j
595 IF (.NOT.proj%init) THEN
596 PRINT '(A)', 'You have not called map_set for this projection'
597 CALL wrf_error_fatal ( 'LATLON_TO_IJ' )
600 SELECT CASE(proj%code)
603 CALL llij_latlon(lat,lon,proj,i,j)
606 CALL llij_merc(lat,lon,proj,i,j)
609 CALL llij_ps(lat,lon,proj,i,j)
612 CALL llij_ps_wgs84(lat,lon,proj,i,j)
614 CASE(PROJ_ALBERS_NAD83)
615 CALL llij_albers_nad83(lat,lon,proj,i,j)
618 CALL llij_lc(lat,lon,proj,i,j)
621 CALL llij_gauss(lat,lon,proj,i,j)
624 CALL llij_cyl(lat,lon,proj,i,j)
627 CALL llij_cassini(lat,lon,proj,i,j)
630 CALL llij_rotlatlon(lat,lon,proj,i,j)
633 PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code
634 CALL wrf_error_fatal ( 'LATLON_TO_IJ' )
640 END SUBROUTINE latlon_to_ij
643 SUBROUTINE ij_to_latlon(proj, i, j, lat, lon)
644 ! Computes geographical latitude and longitude for a given (i,j) point
645 ! in a grid with a projection of proj
648 TYPE(proj_info),INTENT(IN) :: proj
649 REAL, INTENT(IN) :: i
650 REAL, INTENT(IN) :: j
651 REAL, INTENT(OUT) :: lat
652 REAL, INTENT(OUT) :: lon
654 IF (.NOT.proj%init) THEN
655 PRINT '(A)', 'You have not called map_set for this projection'
656 CALL wrf_error_fatal ( 'IJ_TO_LATLON' )
658 SELECT CASE (proj%code)
661 CALL ijll_latlon(i, j, proj, lat, lon)
664 CALL ijll_merc(i, j, proj, lat, lon)
667 CALL ijll_ps(i, j, proj, lat, lon)
670 CALL ijll_ps_wgs84(i, j, proj, lat, lon)
672 CASE (PROJ_ALBERS_NAD83)
673 CALL ijll_albers_nad83(i, j, proj, lat, lon)
676 CALL ijll_lc(i, j, proj, lat, lon)
679 CALL ijll_cyl(i, j, proj, lat, lon)
682 CALL ijll_cassini(i, j, proj, lat, lon)
685 CALL ijll_rotlatlon(i, j, proj, lat, lon)
688 PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code
689 CALL wrf_error_fatal ( 'IJ_TO_LATLON' )
693 END SUBROUTINE ij_to_latlon
696 SUBROUTINE set_ps(proj)
697 ! Initializes a polar-stereographic map projection from the partially
698 ! filled proj structure. This routine computes the radius to the
699 ! southwest corner and computes the i/j location of the pole for use
700 ! in llij_ps and ijll_ps.
704 TYPE(proj_info), INTENT(INOUT) :: proj
713 reflon = proj%stdlon + 90.
715 ! Compute numerator term of map scale factor
716 scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
718 ! Compute radius to lower-left (SW) corner
719 ala1 = proj%lat1 * rad_per_deg
720 proj%rsw = proj%rebydx*COS(ala1)*scale_top/(1.+proj%hemi*SIN(ala1))
722 ! Find the pole point
723 alo1 = (proj%lon1 - reflon) * rad_per_deg
724 proj%polei = proj%knowni - proj%rsw * COS(alo1)
725 proj%polej = proj%knownj - proj%hemi * proj%rsw * SIN(alo1)
729 END SUBROUTINE set_ps
732 SUBROUTINE llij_ps(lat,lon,proj,i,j)
733 ! Given latitude (-90 to 90), longitude (-180 to 180), and the
734 ! standard polar-stereographic projection information via the
735 ! public proj structure, this routine returns the i/j indices which
736 ! if within the domain range from 1->nx and 1->ny, respectively.
740 ! Delcare input arguments
741 REAL, INTENT(IN) :: lat
742 REAL, INTENT(IN) :: lon
743 TYPE(proj_info),INTENT(IN) :: proj
745 ! Declare output arguments
746 REAL, INTENT(OUT) :: i !(x-index)
747 REAL, INTENT(OUT) :: j !(y-index)
749 ! Declare local variables
759 reflon = proj%stdlon + 90.
761 ! Compute numerator term of map scale factor
763 scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
765 ! Find radius to desired point
766 ala = lat * rad_per_deg
767 rm = proj%rebydx * COS(ala) * scale_top/(1. + proj%hemi *SIN(ala))
768 alo = (lon - reflon) * rad_per_deg
769 i = proj%polei + rm * COS(alo)
770 j = proj%polej + proj%hemi * rm * SIN(alo)
774 END SUBROUTINE llij_ps
777 SUBROUTINE ijll_ps(i, j, proj, lat, lon)
779 ! This is the inverse subroutine of llij_ps. It returns the
780 ! latitude and longitude of an i/j point given the projection info
785 ! Declare input arguments
786 REAL, INTENT(IN) :: i ! Column
787 REAL, INTENT(IN) :: j ! Row
788 TYPE (proj_info), INTENT(IN) :: proj
790 ! Declare output arguments
791 REAL, INTENT(OUT) :: lat ! -90 -> 90 north
792 REAL, INTENT(OUT) :: lon ! -180 -> 180 East
803 ! Compute the reference longitude by rotating 90 degrees to the east
804 ! to find the longitude line parallel to the positive x-axis.
805 reflon = proj%stdlon + 90.
807 ! Compute numerator term of map scale factor
808 scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
810 ! Compute radius to point of interest
812 yy = (j - proj%polej) * proj%hemi
817 lat = proj%hemi * 90.
820 gi2 = (proj%rebydx * scale_top)**2.
821 lat = deg_per_rad * proj%hemi * ASIN((gi2-r2)/(gi2+r2))
822 arccos = ACOS(xx/SQRT(r2))
824 lon = reflon + deg_per_rad * arccos
826 lon = reflon - deg_per_rad * arccos
830 ! Convert to a -180 -> 180 East convention
831 IF (lon .GT. 180.) lon = lon - 360.
832 IF (lon .LT. -180.) lon = lon + 360.
836 END SUBROUTINE ijll_ps
839 SUBROUTINE set_ps_wgs84(proj)
840 ! Initializes a polar-stereographic map projection (WGS84 ellipsoid)
841 ! from the partially filled proj structure. This routine computes the
842 ! radius to the southwest corner and computes the i/j location of the
843 ! pole for use in llij_ps and ijll_ps.
848 TYPE(proj_info), INTENT(INOUT) :: proj
851 real :: h, mc, tc, t, rho
855 mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
856 tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg)))* &
857 (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
859 ! Find the i/j location of reference lat/lon with respect to the pole of the projection
860 t = sqrt(((1.0-sin(h*proj%lat1*rad_per_deg))/(1.0+sin(h*proj%lat1*rad_per_deg)))* &
861 (((1.0+E_WGS84*sin(h*proj%lat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%lat1*rad_per_deg)) )**E_WGS84 ) )
862 rho = h * (A_WGS84 / proj%dx) * mc * t / tc
863 proj%polei = rho * sin((h*proj%lon1 - h*proj%stdlon)*rad_per_deg)
864 proj%polej = -rho * cos((h*proj%lon1 - h*proj%stdlon)*rad_per_deg)
868 END SUBROUTINE set_ps_wgs84
871 SUBROUTINE llij_ps_wgs84(lat,lon,proj,i,j)
872 ! Given latitude (-90 to 90), longitude (-180 to 180), and the
873 ! standard polar-stereographic projection information via the
874 ! public proj structure, this routine returns the i/j indices which
875 ! if within the domain range from 1->nx and 1->ny, respectively.
880 REAL, INTENT(IN) :: lat
881 REAL, INTENT(IN) :: lon
882 REAL, INTENT(OUT) :: i !(x-index)
883 REAL, INTENT(OUT) :: j !(y-index)
884 TYPE(proj_info),INTENT(IN) :: proj
887 real :: h, mc, tc, t, rho
891 mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
892 tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg)))* &
893 (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
895 t = sqrt(((1.0-sin(h*lat*rad_per_deg))/(1.0+sin(h*lat*rad_per_deg))) * &
896 (((1.0+E_WGS84*sin(h*lat*rad_per_deg))/(1.0-E_WGS84*sin(h*lat*rad_per_deg)))**E_WGS84))
898 ! Find the x/y location of the requested lat/lon with respect to the pole of the projection
899 rho = (A_WGS84 / proj%dx) * mc * t / tc
900 i = h * rho * sin((h*lon - h*proj%stdlon)*rad_per_deg)
901 j = h *(-rho)* cos((h*lon - h*proj%stdlon)*rad_per_deg)
903 ! Get i/j relative to reference i/j
904 i = proj%knowni + (i - proj%polei)
905 j = proj%knownj + (j - proj%polej)
909 END SUBROUTINE llij_ps_wgs84
912 SUBROUTINE ijll_ps_wgs84(i, j, proj, lat, lon)
914 ! This is the inverse subroutine of llij_ps. It returns the
915 ! latitude and longitude of an i/j point given the projection info
921 REAL, INTENT(IN) :: i ! Column
922 REAL, INTENT(IN) :: j ! Row
923 REAL, INTENT(OUT) :: lat ! -90 -> 90 north
924 REAL, INTENT(OUT) :: lon ! -180 -> 180 East
925 TYPE (proj_info), INTENT(IN) :: proj
928 real :: h, mc, tc, t, rho, x, y
929 real :: chi, a, b, c, d
932 x = (i - proj%knowni + proj%polei)
933 y = (j - proj%knownj + proj%polej)
935 mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
936 tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg))) * &
937 (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
939 rho = sqrt((x*proj%dx)**2.0 + (y*proj%dx)**2.0)
940 t = rho * tc / (A_WGS84 * mc)
942 lon = h*proj%stdlon*rad_per_deg + h*atan2(h*x,h*(-y))
944 chi = PI/2.0-2.0*atan(t)
945 a = 1./2.*E_WGS84**2. + 5./24.*E_WGS84**4. + 1./40.*E_WGS84**6. + 73./2016.*E_WGS84**8.
946 b = 7./24.*E_WGS84**4. + 29./120.*E_WGS84**6. + 54113./40320.*E_WGS84**8.
947 c = 7./30.*E_WGS84**6. + 81./280.*E_WGS84**8.
948 d = 4279./20160.*E_WGS84**8.
950 lat = chi + sin(2.*chi)*(a + cos(2.*chi)*(b + cos(2.*chi)*(c + d*cos(2.*chi))))
953 lat = lat*deg_per_rad
954 lon = lon*deg_per_rad
958 END SUBROUTINE ijll_ps_wgs84
961 SUBROUTINE set_albers_nad83(proj)
962 ! Initializes an Albers equal area map projection (NAD83 ellipsoid)
963 ! from the partially filled proj structure. This routine computes the
964 ! radius to the southwest corner and computes the i/j location of the
965 ! pole for use in llij_albers_nad83 and ijll_albers_nad83.
970 TYPE(proj_info), INTENT(INOUT) :: proj
973 real :: h, m1, m2, q1, q2, theta, q, sinphi
977 m1 = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_NAD83*sin(h*proj%truelat1*rad_per_deg))**2.0)
978 m2 = cos(h*proj%truelat2*rad_per_deg)/sqrt(1.0-(E_NAD83*sin(h*proj%truelat2*rad_per_deg))**2.0)
980 sinphi = sin(proj%truelat1*rad_per_deg)
981 q1 = (1.0-E_NAD83**2.0) * &
982 ((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)))
984 sinphi = sin(proj%truelat2*rad_per_deg)
985 q2 = (1.0-E_NAD83**2.0) * &
986 ((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)))
988 if (proj%truelat1 == proj%truelat2) then
989 proj%nc = sin(proj%truelat1*rad_per_deg)
991 proj%nc = (m1**2.0 - m2**2.0) / (q2 - q1)
994 proj%bigc = m1**2.0 + proj%nc*q1
996 ! Find the i/j location of reference lat/lon with respect to the pole of the projection
997 sinphi = sin(proj%lat1*rad_per_deg)
998 q = (1.0-E_NAD83**2.0) * &
999 ((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)))
1001 proj%rho0 = h * (A_NAD83 / proj%dx) * sqrt(proj%bigc - proj%nc * q) / proj%nc
1002 theta = proj%nc*(proj%lon1 - proj%stdlon)*rad_per_deg
1004 proj%polei = proj%rho0 * sin(h*theta)
1005 proj%polej = proj%rho0 - proj%rho0 * cos(h*theta)
1009 END SUBROUTINE set_albers_nad83
1012 SUBROUTINE llij_albers_nad83(lat,lon,proj,i,j)
1013 ! Given latitude (-90 to 90), longitude (-180 to 180), and the
1014 ! standard projection information via the
1015 ! public proj structure, this routine returns the i/j indices which
1016 ! if within the domain range from 1->nx and 1->ny, respectively.
1021 REAL, INTENT(IN) :: lat
1022 REAL, INTENT(IN) :: lon
1023 REAL, INTENT(OUT) :: i !(x-index)
1024 REAL, INTENT(OUT) :: j !(y-index)
1025 TYPE(proj_info),INTENT(IN) :: proj
1028 real :: h, q, rho, theta, sinphi
1032 sinphi = sin(h*lat*rad_per_deg)
1034 ! Find the x/y location of the requested lat/lon with respect to the pole of the projection
1035 q = (1.0-E_NAD83**2.0) * &
1036 ((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)))
1038 rho = h * (A_NAD83 / proj%dx) * sqrt(proj%bigc - proj%nc * q) / proj%nc
1039 theta = proj%nc * (h*lon - h*proj%stdlon)*rad_per_deg
1041 i = h*rho*sin(theta)
1042 j = h*proj%rho0 - h*rho*cos(theta)
1044 ! Get i/j relative to reference i/j
1045 i = proj%knowni + (i - proj%polei)
1046 j = proj%knownj + (j - proj%polej)
1050 END SUBROUTINE llij_albers_nad83
1053 SUBROUTINE ijll_albers_nad83(i, j, proj, lat, lon)
1055 ! This is the inverse subroutine of llij_albers_nad83. It returns the
1056 ! latitude and longitude of an i/j point given the projection info
1062 REAL, INTENT(IN) :: i ! Column
1063 REAL, INTENT(IN) :: j ! Row
1064 REAL, INTENT(OUT) :: lat ! -90 -> 90 north
1065 REAL, INTENT(OUT) :: lon ! -180 -> 180 East
1066 TYPE (proj_info), INTENT(IN) :: proj
1069 real :: h, q, rho, theta, beta, x, y
1074 x = (i - proj%knowni + proj%polei)
1075 y = (j - proj%knownj + proj%polej)
1077 rho = sqrt(x**2.0 + (proj%rho0 - y)**2.0)
1078 theta = atan2(x, proj%rho0-y)
1080 q = (proj%bigc - (rho*proj%nc*proj%dx/A_NAD83)**2.0) / proj%nc
1082 beta = asin(q/(1.0 - log((1.0-E_NAD83)/(1.0+E_NAD83))*(1.0-E_NAD83**2.0)/(2.0*E_NAD83)))
1083 a = 1./3.*E_NAD83**2. + 31./180.*E_NAD83**4. + 517./5040.*E_NAD83**6.
1084 b = 23./360.*E_NAD83**4. + 251./3780.*E_NAD83**6.
1085 c = 761./45360.*E_NAD83**6.
1087 lat = beta + a*sin(2.*beta) + b*sin(4.*beta) + c*sin(6.*beta)
1089 lat = h*lat*deg_per_rad
1090 lon = proj%stdlon + theta*deg_per_rad/proj%nc
1094 END SUBROUTINE ijll_albers_nad83
1097 SUBROUTINE set_lc(proj)
1098 ! Initialize the remaining items in the proj structure for a
1099 ! lambert conformal grid.
1103 TYPE(proj_info), INTENT(INOUT) :: proj
1110 ! Compute cone factor
1111 CALL lc_cone(proj%truelat1, proj%truelat2, proj%cone)
1113 ! Compute longitude differences and ensure we stay out of the
1114 ! forbidden "cut zone"
1115 deltalon1 = proj%lon1 - proj%stdlon
1116 IF (deltalon1 .GT. +180.) deltalon1 = deltalon1 - 360.
1117 IF (deltalon1 .LT. -180.) deltalon1 = deltalon1 + 360.
1119 ! Convert truelat1 to radian and compute COS for later use
1120 tl1r = proj%truelat1 * rad_per_deg
1123 ! Compute the radius to our known lower-left (SW) corner
1124 proj%rsw = proj%rebydx * ctl1r/proj%cone * &
1125 (TAN((90.*proj%hemi-proj%lat1)*rad_per_deg/2.) / &
1126 TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone
1129 arg = proj%cone*(deltalon1*rad_per_deg)
1130 proj%polei = proj%hemi*proj%knowni - proj%hemi * proj%rsw * SIN(arg)
1131 proj%polej = proj%hemi*proj%knownj + proj%rsw * COS(arg)
1135 END SUBROUTINE set_lc
1138 SUBROUTINE lc_cone(truelat1, truelat2, cone)
1140 ! Subroutine to compute the cone factor of a Lambert Conformal projection
1145 REAL, INTENT(IN) :: truelat1 ! (-90 -> 90 degrees N)
1146 REAL, INTENT(IN) :: truelat2 ! " " " " "
1149 REAL, INTENT(OUT) :: cone
1155 ! First, see if this is a secant or tangent projection. For tangent
1156 ! projections, truelat1 = truelat2 and the cone is tangent to the
1157 ! Earth's surface at this latitude. For secant projections, the cone
1158 ! intersects the Earth's surface at each of the distinctly different
1160 IF (ABS(truelat1-truelat2) .GT. 0.1) THEN
1161 cone = ALOG10(COS(truelat1*rad_per_deg)) - &
1162 ALOG10(COS(truelat2*rad_per_deg))
1163 cone = cone /(ALOG10(TAN((45.0 - ABS(truelat1)/2.0) * rad_per_deg)) - &
1164 ALOG10(TAN((45.0 - ABS(truelat2)/2.0) * rad_per_deg)))
1166 cone = SIN(ABS(truelat1)*rad_per_deg )
1171 END SUBROUTINE lc_cone
1174 SUBROUTINE ijll_lc( i, j, proj, lat, lon)
1176 ! Subroutine to convert from the (i,j) cartesian coordinate to the
1177 ! geographical latitude and longitude for a Lambert Conformal projection.
1180 ! 25 Jul 01: Corrected by B. Shaw, NOAA/FSL
1185 REAL, INTENT(IN) :: i ! Cartesian X coordinate
1186 REAL, INTENT(IN) :: j ! Cartesian Y coordinate
1187 TYPE(proj_info),INTENT(IN) :: proj ! Projection info structure
1190 REAL, INTENT(OUT) :: lat ! Latitude (-90->90 deg N)
1191 REAL, INTENT(OUT) :: lon ! Longitude (-180->180 E)
1197 REAL :: chi,chi1,chi2
1204 chi1 = (90. - proj%hemi*proj%truelat1)*rad_per_deg
1205 chi2 = (90. - proj%hemi*proj%truelat2)*rad_per_deg
1207 ! See if we are in the southern hemispere and flip the indices
1209 inew = proj%hemi * i
1210 jnew = proj%hemi * j
1212 ! Compute radius**2 to i/j location
1213 xx = inew - proj%polei
1214 yy = proj%polej - jnew
1215 r2 = (xx*xx + yy*yy)
1216 r = SQRT(r2)/proj%rebydx
1218 ! Convert to lat/lon
1219 IF (r2 .EQ. 0.) THEN
1220 lat = proj%hemi * 90.
1225 lon = proj%stdlon + deg_per_rad * ATAN2(proj%hemi*xx,yy)/proj%cone
1226 lon = MOD(lon+360., 360.)
1228 ! Latitude. Latitude determined by solving an equation adapted
1230 ! Maling, D.H., 1973: Coordinate Systems and Map Projections
1231 ! Equations #20 in Appendix I.
1233 IF (chi1 .EQ. chi2) THEN
1234 chi = 2.0*ATAN( ( r/TAN(chi1) )**(1./proj%cone) * TAN(chi1*0.5) )
1236 chi = 2.0*ATAN( (r*proj%cone/SIN(chi1))**(1./proj%cone) * TAN(chi1*0.5))
1238 lat = (90.0-chi*deg_per_rad)*proj%hemi
1242 IF (lon .GT. +180.) lon = lon - 360.
1243 IF (lon .LT. -180.) lon = lon + 360.
1247 END SUBROUTINE ijll_lc
1250 SUBROUTINE llij_lc( lat, lon, proj, i, j)
1252 ! Subroutine to compute the geographical latitude and longitude values
1253 ! to the cartesian x/y on a Lambert Conformal projection.
1258 REAL, INTENT(IN) :: lat ! Latitude (-90->90 deg N)
1259 REAL, INTENT(IN) :: lon ! Longitude (-180->180 E)
1260 TYPE(proj_info),INTENT(IN) :: proj ! Projection info structure
1263 REAL, INTENT(OUT) :: i ! Cartesian X coordinate
1264 REAL, INTENT(OUT) :: j ! Cartesian Y coordinate
1276 ! Compute deltalon between known longitude and standard lon and ensure
1277 ! it is not in the cut zone
1278 deltalon = lon - proj%stdlon
1279 IF (deltalon .GT. +180.) deltalon = deltalon - 360.
1280 IF (deltalon .LT. -180.) deltalon = deltalon + 360.
1282 ! Convert truelat1 to radian and compute COS for later use
1283 tl1r = proj%truelat1 * rad_per_deg
1286 ! Radius to desired point
1287 rm = proj%rebydx * ctl1r/proj%cone * &
1288 (TAN((90.*proj%hemi-lat)*rad_per_deg/2.) / &
1289 TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone
1291 arg = proj%cone*(deltalon*rad_per_deg)
1292 i = proj%polei + proj%hemi * rm * SIN(arg)
1293 j = proj%polej - rm * COS(arg)
1295 ! Finally, if we are in the southern hemisphere, flip the i/j
1296 ! values to a coordinate system where (1,1) is the SW corner
1297 ! (what we assume) which is different than the original NCEP
1298 ! algorithms which used the NE corner as the origin in the
1299 ! southern hemisphere (left-hand vs. right-hand coordinate?)
1304 END SUBROUTINE llij_lc
1307 SUBROUTINE set_merc(proj)
1309 ! Sets up the remaining basic elements for the mercator projection
1312 TYPE(proj_info), INTENT(INOUT) :: proj
1316 ! Preliminary variables
1318 clain = COS(rad_per_deg*proj%truelat1)
1319 proj%dlon = proj%dx / (proj%re_m * clain)
1321 ! Compute distance from equator to origin, and store in the
1325 IF (proj%lat1 .NE. 0.) THEN
1326 proj%rsw = (ALOG(TAN(0.5*((proj%lat1+90.)*rad_per_deg))))/proj%dlon
1331 END SUBROUTINE set_merc
1334 SUBROUTINE llij_merc(lat, lon, proj, i, j)
1336 ! Compute i/j coordinate from lat lon for mercator projection
1339 REAL, INTENT(IN) :: lat
1340 REAL, INTENT(IN) :: lon
1341 TYPE(proj_info),INTENT(IN) :: proj
1342 REAL,INTENT(OUT) :: i
1343 REAL,INTENT(OUT) :: j
1346 deltalon = lon - proj%lon1
1347 IF (deltalon .LT. -180.) deltalon = deltalon + 360.
1348 IF (deltalon .GT. 180.) deltalon = deltalon - 360.
1349 i = proj%knowni + (deltalon/(proj%dlon*deg_per_rad))
1350 j = proj%knownj + (ALOG(TAN(0.5*((lat + 90.) * rad_per_deg)))) / &
1351 proj%dlon - proj%rsw
1355 END SUBROUTINE llij_merc
1358 SUBROUTINE ijll_merc(i, j, proj, lat, lon)
1360 ! Compute the lat/lon from i/j for mercator projection
1363 REAL,INTENT(IN) :: i
1364 REAL,INTENT(IN) :: j
1365 TYPE(proj_info),INTENT(IN) :: proj
1366 REAL, INTENT(OUT) :: lat
1367 REAL, INTENT(OUT) :: lon
1370 lat = 2.0*ATAN(EXP(proj%dlon*(proj%rsw + j-proj%knownj)))*deg_per_rad - 90.
1371 lon = (i-proj%knowni)*proj%dlon*deg_per_rad + proj%lon1
1372 IF (lon.GT.180.) lon = lon - 360.
1373 IF (lon.LT.-180.) lon = lon + 360.
1376 END SUBROUTINE ijll_merc
1379 SUBROUTINE llij_latlon(lat, lon, proj, i, j)
1381 ! Compute the i/j location of a lat/lon on a LATLON grid.
1383 REAL, INTENT(IN) :: lat
1384 REAL, INTENT(IN) :: lon
1385 TYPE(proj_info), INTENT(IN) :: proj
1386 REAL, INTENT(OUT) :: i
1387 REAL, INTENT(OUT) :: j
1392 ! Compute deltalat and deltalon as the difference between the input
1393 ! lat/lon and the origin lat/lon
1394 deltalat = lat - proj%lat1
1395 deltalon = lon - proj%lon1
1398 i = deltalon/proj%loninc
1399 j = deltalat/proj%latinc
1406 END SUBROUTINE llij_latlon
1409 SUBROUTINE ijll_latlon(i, j, proj, lat, lon)
1411 ! Compute the lat/lon location of an i/j on a LATLON grid.
1413 REAL, INTENT(IN) :: i
1414 REAL, INTENT(IN) :: j
1415 TYPE(proj_info), INTENT(IN) :: proj
1416 REAL, INTENT(OUT) :: lat
1417 REAL, INTENT(OUT) :: lon
1419 REAL :: i_work, j_work
1423 i_work = i - proj%knowni
1424 j_work = j - proj%knownj
1426 ! Compute deltalat and deltalon
1427 deltalat = j_work*proj%latinc
1428 deltalon = i_work*proj%loninc
1430 lat = proj%lat1 + deltalat
1431 lon = proj%lon1 + deltalon
1435 END SUBROUTINE ijll_latlon
1438 SUBROUTINE set_cyl(proj)
1443 type(proj_info), intent(inout) :: proj
1447 END SUBROUTINE set_cyl
1450 SUBROUTINE llij_cyl(lat, lon, proj, i, j)
1455 real, intent(in) :: lat, lon
1456 real, intent(out) :: i, j
1457 type(proj_info), intent(in) :: proj
1463 ! Compute deltalat and deltalon as the difference between the input
1464 ! lat/lon and the origin lat/lon
1465 deltalat = lat - proj%lat1
1466 ! deltalon = lon - proj%stdlon
1467 deltalon = lon - proj%lon1
1469 if (deltalon < 0.) deltalon = deltalon + 360.
1470 if (deltalon > 360.) deltalon = deltalon - 360.
1473 i = deltalon/proj%loninc
1474 j = deltalat/proj%latinc
1476 if (i <= 0.) i = i + 360./proj%loninc
1477 if (i > 360./proj%loninc) i = i - 360./proj%loninc
1482 END SUBROUTINE llij_cyl
1485 SUBROUTINE ijll_cyl(i, j, proj, lat, lon)
1490 real, intent(in) :: i, j
1491 real, intent(out) :: lat, lon
1492 type(proj_info), intent(in) :: proj
1497 real :: i_work, j_work
1499 i_work = i - proj%knowni
1500 j_work = j - proj%knownj
1502 if (i_work < 0.) i_work = i_work + 360./proj%loninc
1503 if (i_work >= 360./proj%loninc) i_work = i_work - 360./proj%loninc
1505 ! Compute deltalat and deltalon
1506 deltalat = j_work*proj%latinc
1507 deltalon = i_work*proj%loninc
1509 lat = deltalat + proj%lat1
1510 ! lon = deltalon + proj%stdlon
1511 lon = deltalon + proj%lon1
1513 if (lon < -180.) lon = lon + 360.
1514 if (lon > 180.) lon = lon - 360.
1516 END SUBROUTINE ijll_cyl
1519 SUBROUTINE set_cassini(proj)
1524 type(proj_info), intent(inout) :: proj
1527 real :: comp_lat, comp_lon
1528 logical :: global_domain
1532 ! Try to determine whether this domain has global coverage
1533 if (abs(proj%lat1 - proj%latinc/2. + 90.) < 0.001 .and. &
1534 abs(mod(proj%lon1 - proj%loninc/2. - proj%stdlon,360.)) < 0.001) then
1535 global_domain = .true.
1537 global_domain = .false.
1540 if (abs(proj%lat0) /= 90. .and. .not.global_domain) then
1541 call rotate_coords(proj%lat1,proj%lon1,comp_lat,comp_lon,proj%lat0,proj%lon0,proj%stdlon,-1)
1542 proj%lat1 = comp_lat
1543 proj%lon1 = comp_lon
1546 END SUBROUTINE set_cassini
1549 SUBROUTINE llij_cassini(lat, lon, proj, i, j)
1554 real, intent(in) :: lat, lon
1555 real, intent(out) :: i, j
1556 type(proj_info), intent(in) :: proj
1559 real :: comp_lat, comp_lon
1561 ! Convert geographic to computational lat/lon
1562 if (abs(proj%lat0) /= 90.) then
1563 call rotate_coords(lat,lon,comp_lat,comp_lon,proj%lat0,proj%lon0,proj%stdlon,-1)
1569 ! Convert computational lat/lon to i/j
1570 call llij_cyl(comp_lat, comp_lon, proj, i, j)
1572 END SUBROUTINE llij_cassini
1575 SUBROUTINE ijll_cassini(i, j, proj, lat, lon)
1580 real, intent(in) :: i, j
1581 real, intent(out) :: lat, lon
1582 type(proj_info), intent(in) :: proj
1585 real :: comp_lat, comp_lon
1587 ! Convert i/j to computational lat/lon
1588 call ijll_cyl(i, j, proj, comp_lat, comp_lon)
1590 ! Convert computational to geographic lat/lon
1591 if (abs(proj%lat0) /= 90.) then
1592 call rotate_coords(comp_lat,comp_lon,lat,lon,proj%lat0,proj%lon0,proj%stdlon,1)
1598 END SUBROUTINE ijll_cassini
1601 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1602 ! Purpose: Converts between computational and geographic lat/lon for Cassini
1604 ! Notes: This routine was provided by Bill Skamarock, 2007-03-27
1605 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1606 SUBROUTINE rotate_coords(ilat,ilon,olat,olon,lat_np,lon_np,lon_0,direction)
1610 REAL, INTENT(IN ) :: ilat, ilon
1611 REAL, INTENT( OUT) :: olat, olon
1612 REAL, INTENT(IN ) :: lat_np, lon_np, lon_0
1613 INTEGER, INTENT(IN ), OPTIONAL :: direction
1614 ! >=0, default : computational -> geographical
1615 ! < 0 : geographical -> computational
1618 REAL :: phi_np, lam_np, lam_0, dlam
1619 REAL :: sinphi, cosphi, coslam, sinlam
1621 ! Convert all angles to radians
1622 phi_np = lat_np * rad_per_deg
1623 lam_np = lon_np * rad_per_deg
1624 lam_0 = lon_0 * rad_per_deg
1625 rlat = ilat * rad_per_deg
1626 rlon = ilon * rad_per_deg
1628 IF ( PRESENT(direction) ) THEN
1629 IF (direction < 0) THEN
1630 ! The equations are exactly the same except for one small difference
1631 ! with respect to longitude ...
1639 sinphi = COS(phi_np)*COS(rlat)*COS(rlon-dlam) + SIN(phi_np)*SIN(rlat)
1640 cosphi = SQRT(1.-sinphi*sinphi)
1641 coslam = SIN(phi_np)*COS(rlat)*COS(rlon-dlam) - COS(phi_np)*SIN(rlat)
1642 sinlam = COS(rlat)*SIN(rlon-dlam)
1643 IF ( cosphi /= 0. ) THEN
1644 coslam = coslam/cosphi
1645 sinlam = sinlam/cosphi
1647 olat = deg_per_rad*ASIN(sinphi)
1648 olon = deg_per_rad*(ATAN2(sinlam,coslam)-dlam-lam_0+lam_np)
1649 ! Both of my F90 text books prefer the DO-EXIT form, and claim it is faster
1650 ! when optimization is turned on (as we will always do...)
1652 IF (olon >= -180.) EXIT
1656 IF (olon <= 180.) EXIT
1660 END SUBROUTINE rotate_coords
1663 SUBROUTINE llij_rotlatlon(lat, lon, proj, i_real, j_real)
1668 REAL, INTENT(IN) :: lat, lon
1670 REAL, INTENT(OUT) :: i_real, j_real
1671 TYPE (proj_info), INTENT(IN) :: proj
1674 INTEGER :: ii,imt,jj,jmt,k,krows,ncol,nrow,iri
1675 REAL(KIND=HIGH) :: dphd,dlmd !Grid increments, degrees
1676 REAL(KIND=HIGH) :: glatd !Geographic latitude, positive north
1677 REAL(KIND=HIGH) :: glond !Geographic longitude, positive west
1678 REAL(KIND=HIGH) :: col,d1,d2,d2r,dlm,dlm1,dlm2,dph,glat,glon, &
1679 pi,r2d,row,tlat,tlat1,tlat2, &
1680 tlon,tlon1,tlon2,tph0,tlm0,x,y,z
1685 dphd = proj%phi/REAL((proj%jydim-1)/2)
1686 dlmd = proj%lambda/REAL(proj%ixdim-1)
1692 imt = 2*proj%ixdim-1
1693 jmt = proj%jydim/2+1
1699 tph0 = proj%lat1*d2r
1700 tlm0 = -proj%lon1*d2r
1702 x = COS(tph0)*COS(glat)*COS(glon-tlm0)+SIN(tph0)*SIN(glat)
1703 y = -COS(glat)*SIN(glon-tlm0)
1704 z = COS(tph0)*SIN(glat)-SIN(tph0)*COS(glat)*COS(glon-tlm0)
1705 tlat = r2d*ATAN(z/SQRT(x*x+y*y))
1706 tlon = r2d*ATAN(y/x)
1709 col = tlon/dlmd+proj%ixdim
1711 if ( (row - INT(row)) .gt. 0.999) then
1713 else if ( (col - INT(col)) .gt. 0.999) then
1727 IF (proj%stagger == HH) THEN
1729 IF (mod(nrow,2) .eq. 0) then
1732 i_real = col / 2.0 + 0.5
1737 IF ((abs(MOD(nrow,2)) == 1 .AND. abs(MOD(ncol,2)) == 1) .OR. &
1738 (MOD(nrow,2) == 0 .AND. MOD(ncol,2) == 0)) THEN
1740 tlat1 = (nrow-jmt)*dph
1742 tlon1 = (ncol-proj%ixdim)*dlm
1747 d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1748 d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1756 tlat1 = (nrow+1-jmt)*dph
1758 tlon1 = (ncol-proj%ixdim)*dlm
1762 d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1763 d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1772 ELSE IF (proj%stagger == VV) THEN
1774 IF (mod(nrow,2) .eq. 0) then
1775 i_real = col / 2.0 + 0.5
1781 IF ((MOD(nrow,2) == 0 .AND. abs(MOD(ncol,2)) == 1) .OR. &
1782 (abs(MOD(nrow,2)) == 1 .AND. MOD(ncol,2) == 0)) THEN
1783 tlat1 = (nrow-jmt)*dph
1785 tlon1 = (ncol-proj%ixdim)*dlm
1789 d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1790 d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1798 tlat1 = (nrow+1-jmt)*dph
1800 tlon1 = (ncol-proj%ixdim)*dlm
1804 d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1805 d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1816 !!! Added next line as a Kludge - not yet understood why needed
1817 if (ncol .le. 0) ncol=ncol-1
1822 IF (proj%stagger == HH) THEN
1823 IF (abs(MOD(jj,2)) == 1) ii = ii+1
1824 ELSE IF (proj%stagger == VV) THEN
1825 IF (MOD(jj,2) == 0) ii=ii+1
1831 END SUBROUTINE llij_rotlatlon
1834 SUBROUTINE ijll_rotlatlon(i, j, proj, lat,lon)
1839 REAL, INTENT(IN) :: i, j
1840 REAL, INTENT(OUT) :: lat, lon
1841 TYPE (proj_info), INTENT(IN) :: proj
1845 INTEGER :: midcol,midrow,ncol,iadd1,iadd2,imt,jh2,knrow,krem,kv,nrow
1846 REAL :: i_work, j_work
1847 REAL :: dphd,dlmd !Grid increments, degrees
1848 REAL(KIND=HIGH) :: arg1,arg2,d2r,fctr,glatr,glatd,glond,pi, &
1849 r2d,tlatd,tlond,tlatr,tlonr,tlm0,tph0
1855 if ( (j - INT(j)) .gt. 0.999) then
1861 dphd = proj%phi/REAL((proj%jydim-1)/2)
1862 dlmd = proj%lambda/REAL(proj%ixdim-1)
1867 tph0 = proj%lat1*d2r
1868 tlm0 = -proj%lon1*d2r
1870 midrow = (proj%jydim+1)/2
1873 col = 2*i_work-1+abs(MOD(jh+1,2))
1874 tlatd = (j_work-midrow)*dphd
1875 tlond = (col-midcol)*dlmd
1877 IF (proj%stagger == VV) THEN
1878 if (mod(jh,2) .eq. 0) then
1879 tlond = tlond - DLMD
1881 tlond = tlond + DLMD
1887 arg1 = SIN(tlatr)*COS(tph0)+COS(tlatr)*SIN(tph0)*COS(tlonr)
1892 arg2 = COS(tlatr)*COS(tlonr)/(COS(glatr)*COS(tph0))-TAN(glatr)*TAN(tph0)
1893 IF (ABS(arg2) > 1.) arg2 = ABS(arg2)/arg2
1895 IF (tlond > 0.) fctr = -1.
1897 glond = tlm0*r2d+fctr*ACOS(arg2)*r2d
1902 IF (lon .GT. +180.) lon = lon - 360.
1903 IF (lon .LT. -180.) lon = lon + 360.
1905 END SUBROUTINE ijll_rotlatlon
1908 SUBROUTINE set_gauss(proj)
1913 type (proj_info), intent(inout) :: proj
1915 ! Initialize the array that will hold the Gaussian latitudes.
1917 IF ( ASSOCIATED( proj%gauss_lat ) ) THEN
1918 DEALLOCATE ( proj%gauss_lat )
1921 ! Get the needed space for our array.
1923 ALLOCATE ( proj%gauss_lat(proj%nlat*2) )
1925 ! Compute the Gaussian latitudes.
1927 CALL gausll( proj%nlat*2 , proj%gauss_lat )
1929 ! Now, these could be upside down from what we want, so let's check.
1930 ! We take advantage of the equatorial symmetry to remove any sort of
1931 ! array re-ordering.
1933 IF ( ABS(proj%gauss_lat(1) - proj%lat1) .GT. 0.01 ) THEN
1934 proj%gauss_lat = -1. * proj%gauss_lat
1937 ! Just a sanity check.
1939 IF ( ABS(proj%gauss_lat(1) - proj%lat1) .GT. 0.01 ) THEN
1940 PRINT '(A)','Oops, something is not right with the Gaussian latitude computation.'
1941 PRINT '(A,F8.3,A)','The input data gave the starting latitude as ',proj%lat1,'.'
1942 PRINT '(A,F8.3,A)','This routine computed the starting latitude as +-',ABS(proj%gauss_lat(1)),'.'
1943 PRINT '(A,F8.3,A)','The difference is larger than 0.01 degrees, which is not expected.'
1944 CALL wrf_error_fatal ( 'Gaussian_latitude_computation' )
1947 END SUBROUTINE set_gauss
1950 SUBROUTINE gausll ( nlat , lat_sp )
1955 REAL (KIND=HIGH) , PARAMETER :: pi = 3.141592653589793
1956 REAL (KIND=HIGH) , DIMENSION(nlat) :: cosc , gwt , sinc , colat , wos2 , lat
1957 REAL , DIMENSION(nlat) :: lat_sp
1959 CALL lggaus(nlat, cosc, gwt, sinc, colat, wos2)
1962 lat(i) = ACOS(sinc(i)) * 180._HIGH / pi
1963 IF (i.gt.nlat/2) lat(i) = -lat(i)
1968 END SUBROUTINE gausll
1971 SUBROUTINE lggaus( nlat, cosc, gwt, sinc, colat, wos2 )
1975 ! LGGAUS finds the Gaussian latitudes by finding the roots of the
1976 ! ordinary Legendre polynomial of degree NLAT using Newton's
1980 integer NLAT ! the number of latitudes (degree of the polynomial)
1982 ! On exit: for each Gaussian latitude
1983 ! COSC - cos(colatitude) or sin(latitude)
1984 ! GWT - the Gaussian weights
1985 ! SINC - sin(colatitude) or cos(latitude)
1986 ! COLAT - the colatitudes in radians
1987 ! WOS2 - Gaussian weight over sin**2(colatitude)
1989 REAL (KIND=HIGH) , DIMENSION(nlat) :: cosc , gwt , sinc , colat , wos2
1990 REAL (KIND=HIGH) , PARAMETER :: pi = 3.141592653589793
1992 ! Convergence criterion for iteration of cos latitude
1994 REAL , PARAMETER :: xlim = 1.0E-14
1996 INTEGER :: nzero, i, j
1997 REAL (KIND=HIGH) :: fi, fi1, a, b, g, gm, gp, gt, delta, c, d
1999 ! The number of zeros between pole and equator
2003 ! Set first guess for cos(colat)
2006 cosc(i) = SIN( (i-0.5)*pi/nlat + pi*0.5 )
2009 ! Constants for determining the derivative of the polynomial
2012 a = fi*fi1 / SQRT(4.0*fi1*fi1-1.0)
2013 b = fi1*fi / SQRT(4.0*fi*fi-1.0)
2015 ! Loop over latitudes, iterating the search for each root
2020 ! Determine the value of the ordinary Legendre polynomial for
2021 ! the current guess root
2024 CALL lgord( g, cosc(i), nlat )
2026 ! Determine the derivative of the polynomial at this point
2028 CALL lgord( gm, cosc(i), nlat-1 )
2029 CALL lgord( gp, cosc(i), nlat+1 )
2030 gt = (cosc(i)*cosc(i)-1.0) / (a*gp-b*gm)
2032 ! Update the estimate of the root
2035 cosc(i) = cosc(i) - delta
2037 ! If convergence criterion has not been met, keep trying
2040 IF( ABS(delta).GT.xlim ) CYCLE
2042 ! Determine the Gaussian weights
2044 c = 2.0 *( 1.0-cosc(i)*cosc(i) )
2045 CALL lgord( d, cosc(i), nlat-1 )
2047 gwt(i) = c *( fi-0.5 ) / d
2054 ! Determine the colatitudes and sin(colat) and weights over sin**2
2057 colat(i)= ACOS(cosc(i))
2058 sinc(i) = SIN(colat(i))
2059 wos2(i) = gwt(i) /( sinc(i)*sinc(i) )
2062 ! If NLAT is odd, set values at the equator
2064 IF( MOD(nlat,2) .NE. 0 ) THEN
2068 CALL lgord( d, cosc(i), nlat-1 )
2070 gwt(i) = c *( fi-0.5 ) / d
2076 ! Determine the southern hemisphere values by symmetry
2078 DO i=nlat-nzero+1,nlat
2079 cosc(i) =-cosc(nlat+1-i)
2080 gwt(i) = gwt(nlat+1-i)
2081 colat(i)= pi-colat(nlat+1-i)
2082 sinc(i) = sinc(nlat+1-i)
2083 wos2(i) = wos2(nlat+1-i)
2086 END SUBROUTINE lggaus
2089 SUBROUTINE lgord( f, cosc, n )
2093 ! LGORD calculates the value of an ordinary Legendre polynomial at a
2094 ! specific latitude.
2097 ! cosc - COS(colatitude)
2098 ! n - the degree of the polynomial
2101 ! f - the value of the Legendre polynomial of degree N at
2102 ! latitude ASIN(cosc)
2104 REAL (KIND=HIGH) :: s1, c4, a, b, fk, f, cosc, colat, c1, fn, ang
2107 ! Determine the colatitude
2113 c1 = c1 * SQRT( 1.0 - 1.0/(4*k*k) )
2123 IF (k.eq.n) c4 = 0.5 * c4
2124 s1 = s1 + c4 * COS(ang)
2128 ang= colat * (fn-fk-2.0)
2129 c4 = ( a * (fn-b+1.0) / ( b * (fn+fn-a) ) ) * c4
2134 END SUBROUTINE lgord
2137 SUBROUTINE llij_gauss (lat, lon, proj, i, j)
2141 REAL , INTENT(IN) :: lat, lon
2142 REAL , INTENT(OUT) :: i, j
2143 TYPE (proj_info), INTENT(IN) :: proj
2145 INTEGER :: n , n_low
2146 LOGICAL :: found = .FALSE.
2147 REAL :: diff_1 , diff_nlat
2149 ! The easy one first, get the x location. The calling routine has already made
2150 ! sure that the necessary assumptions concerning the sign of the deltalon and the
2151 ! relative east/west'ness of the longitude and the starting longitude are consistent
2152 ! to allow this easy computation.
2154 i = ( lon - proj%lon1 ) / proj%loninc + 1.
2156 ! Since this is a global data set, we need to be concerned about wrapping the
2157 ! fields around the globe.
2159 ! IF ( ( proj%loninc .GT. 0 ) .AND. &
2160 ! ( FLOOR((lon-proj%lon1)/proj%loninc) + 1 .GE. proj%ixdim ) .AND. &
2161 ! ( lon + proj%loninc .GE. proj%lon1 + 360 ) ) THEN
2162 !! BUG: We may need to set proj%wrap, but proj is intent(in)
2163 !! WHAT IS THIS USED FOR?
2164 !! proj%wrap = .TRUE.
2166 ! ELSE IF ( ( proj%loninc .LT. 0 ) .AND. &
2167 ! ( FLOOR((lon-proj%lon1)/proj%loninc) + 1 .GE. proj%ixdim ) .AND. &
2168 ! ( lon + proj%loninc .LE. proj%lon1 - 360 ) ) THEN
2169 ! ! BUG: We may need to set proj%wrap, but proj is intent(in)
2170 ! ! WHAT IS THIS USED FOR?
2171 ! ! proj%wrap = .TRUE.
2175 ! Yet another quicky test, can we find bounding values? If not, then we may be
2176 ! dealing with putting data to a polar projection, so just give them them maximal
2177 ! value for the location. This is an OK assumption for the interpolation across the
2178 ! top of the pole, given how close the longitude lines are.
2180 IF ( ABS(lat) .GT. ABS(proj%gauss_lat(1)) ) THEN
2182 diff_1 = lat - proj%gauss_lat(1)
2183 diff_nlat = lat - proj%gauss_lat(proj%nlat*2)
2185 IF ( ABS(diff_1) .LT. ABS(diff_nlat) ) THEN
2191 ! If the latitude is between the two bounding values, we have to search and interpolate.
2195 DO n = 1 , proj%nlat*2 -1
2196 IF ( ( proj%gauss_lat(n) - lat ) * ( proj%gauss_lat(n+1) - lat ) .LE. 0 ) THEN
2203 ! Everything still OK?
2205 IF ( .NOT. found ) THEN
2206 PRINT '(A)','Troubles in river city. No bounding values of latitude found in the Gaussian routines.'
2207 CALL wrf_error_fatal ( 'Gee_no_bounding_lats_Gaussian' )
2210 j = ( ( proj%gauss_lat(n_low) - lat ) * ( n_low + 1 ) + &
2211 ( lat - proj%gauss_lat(n_low+1) ) * ( n_low ) ) / &
2212 ( proj%gauss_lat(n_low) - proj%gauss_lat(n_low+1) )
2216 END SUBROUTINE llij_gauss
2218 END MODULE module_llxy