svn trunk commit r4413
[wrffire.git] / wrfv2_fire / share / module_llxy.F
blob33858e9b37fe9ff1c4156b59d6946dbcf200cf96
1 MODULE module_llxy
3 ! Module that defines constants, data structures, and
4 ! subroutines used to convert grid indices to lat/lon
5 ! and vice versa.   
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)
16 ! REMARKS
17 ! -------
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.  
26 ! ASSUMPTIONS
27 ! -----------
28 !  Grid Definition:
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 !       ---------------        -------------      -------------
46 !        SW Corner                  +                   +
47 !        NE Corner                  -                   -
48 !        NW Corner                  -                   +
49 !        SE Corner                  +                   -
51 !  Data Definitions:
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.
68 ! USAGE
69 ! -----
70 ! To use the routines in this module, the calling routines must have the
71 ! following statement at the beginning of its declaration block:
72 !   USE map_utils
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
80 ! as follows:
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)
87 !       where:
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)
91 !                         (see assumptions!)
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.
117 ! REFERENCES
118 ! ----------
119 !  Hoke, Hayes, and Renninger, "Map Preojections and Grid Systems for
120 !       Meteorological Applications." AFGWC/TN-79/003(Rev), Air Weather
121 !       Service, 1985.
123 !  NCAR MM5v3 Modeling System, REGRIDDER program, module_first_guess_map.F
124 !  NCEP routines w3fb06, w3fb07, w3fb08, w3fb09, w3fb11, w3fb12
126 ! HISTORY
127 ! -------
128 ! 27 Mar 2001 - Original Version
129 !               Brent L. Shaw, NOAA/FSL (CSU/CIRA)
131 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
133    USE module_wrf_error
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
169    TYPE proj_info
171       INTEGER          :: code     ! Integer code for projection TYPE
172       INTEGER          :: nlat     ! For Gaussian -- number of latitude points 
173                                    !  north of the equator 
174       INTEGER          :: nlon     !
175                                    !
176       INTEGER          :: ixdim    ! For Rotated Lat/Lon -- number of mass points
177                                    !  in an odd row
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 
181                                    !  degrees latitude
182       REAL             :: lambda   ! For Rotated Lat/Lon -- domain half-extend in
183                                    !  degrees longitude
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 
213                                    !  ready for use
214       LOGICAL          :: wrap     ! For Gaussian -- flag to indicate wrapping 
215                                    !  around globe?
216       REAL, POINTER, DIMENSION(:) :: gauss_lat  ! Latitude array for Gaussian grid
218    END TYPE proj_info
220  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
221  CONTAINS
222  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
224    SUBROUTINE map_init(proj)
225       ! Initializes the map projection structure to missing values
226   
227       IMPLICIT NONE
228       TYPE(proj_info), INTENT(INOUT)  :: proj
229   
230       proj%lat1     = -999.9
231       proj%lon1     = -999.9
232       proj%lat0     = -999.9
233       proj%lon0     = -999.9
234       proj%dx       = -999.9
235       proj%dy       = -999.9
236       proj%latinc   = -999.9
237       proj%loninc   = -999.9
238       proj%stdlon   = -999.9
239       proj%truelat1 = -999.9
240       proj%truelat2 = -999.9
241       proj%phi      = -999.9
242       proj%lambda   = -999.9
243       proj%ixdim    = -999
244       proj%jydim    = -999
245       proj%stagger  = HH
246       proj%nlat     = 0
247       proj%nlon     = 0
248       proj%hemi     = 0.0
249       proj%cone     = -999.9
250       proj%polei    = -999.9
251       proj%polej    = -999.9
252       proj%rsw      = -999.9
253       proj%knowni   = -999.9
254       proj%knownj   = -999.9
255       proj%re_m     = EARTH_RADIUS_M
256       proj%init     = .FALSE.
257       proj%wrap     = .FALSE.
258       proj%rho0     = 0.
259       proj%nc       = 0.
260       proj%bigc     = 0.
261       nullify(proj%gauss_lat)
262    
263    END SUBROUTINE map_init
266    SUBROUTINE map_set(proj_code, proj, lat1, lon1, lat0, lon0, knowni, knownj, dx, latinc, &
267                       loninc, stdlon, truelat1, truelat2, nlat, nlon, ixdim, jydim, &
268                       stagger, phi, lambda, r_earth)
269       ! Given a partially filled proj_info structure, this routine computes
270       ! polei, polej, rsw, and cone (if LC projection) to complete the 
271       ! structure.  This allows us to eliminate redundant calculations when
272       ! calling the coordinate conversion routines multiple times for the
273       ! same map.
274       ! This will generally be the first routine called when a user wants
275       ! to be able to use the coordinate conversion routines, and it
276       ! will call the appropriate subroutines based on the 
277       ! proj%code which indicates which projection type this is.
278   
279       IMPLICIT NONE
280       
281       ! Declare arguments
282       INTEGER, INTENT(IN)               :: proj_code
283       INTEGER, INTENT(IN), OPTIONAL     :: nlat
284       INTEGER, INTENT(IN), OPTIONAL     :: nlon
285       INTEGER, INTENT(IN), OPTIONAL     :: ixdim
286       INTEGER, INTENT(IN), OPTIONAL     :: jydim
287       INTEGER, INTENT(IN), OPTIONAL     :: stagger
288       REAL, INTENT(IN), OPTIONAL        :: latinc
289       REAL, INTENT(IN), OPTIONAL        :: loninc
290       REAL, INTENT(IN), OPTIONAL        :: lat1
291       REAL, INTENT(IN), OPTIONAL        :: lon1
292       REAL, INTENT(IN), OPTIONAL        :: lat0
293       REAL, INTENT(IN), OPTIONAL        :: lon0
294       REAL, INTENT(IN), OPTIONAL        :: dx
295       REAL, INTENT(IN), OPTIONAL        :: stdlon
296       REAL, INTENT(IN), OPTIONAL        :: truelat1
297       REAL, INTENT(IN), OPTIONAL        :: truelat2
298       REAL, INTENT(IN), OPTIONAL        :: knowni
299       REAL, INTENT(IN), OPTIONAL        :: knownj
300       REAL, INTENT(IN), OPTIONAL        :: phi
301       REAL, INTENT(IN), OPTIONAL        :: lambda
302       REAL, INTENT(IN), OPTIONAL        :: r_earth
303       TYPE(proj_info), INTENT(OUT)      :: proj
305       INTEGER :: iter
306       REAL :: dummy_lon1
307       REAL :: dummy_lon0
308       REAL :: dummy_stdlon
309   
310       ! First, verify that mandatory parameters are present for the specified proj_code
311       IF ( proj_code == PROJ_LC ) 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, knowni, knownj, stdlon, dx'
322             CALL wrf_error_fatal ( 'MAP_INIT' )
323          END IF
324       ELSE IF ( proj_code == PROJ_PS ) 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(stdlon) .OR. &
331               .NOT.PRESENT(dx) ) THEN
332             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
333             PRINT '(A)', ' truelat1, lat1, lon1, knonwi, knownj, stdlon, dx'
334             CALL wrf_error_fatal ( 'MAP_INIT' )
335          END IF
336       ELSE IF ( proj_code == PROJ_PS_WGS84 ) THEN
337          IF ( .NOT.PRESENT(truelat1) .OR. &
338               .NOT.PRESENT(lat1) .OR. &
339               .NOT.PRESENT(lon1) .OR. &
340               .NOT.PRESENT(knowni) .OR. &
341               .NOT.PRESENT(knownj) .OR. &
342               .NOT.PRESENT(stdlon) .OR. &
343               .NOT.PRESENT(dx) ) THEN
344             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
345             PRINT '(A)', ' truelat1, lat1, lon1, knonwi, knownj, stdlon, dx'
346             CALL wrf_error_fatal ( 'MAP_INIT' )
347          END IF
348       ELSE IF ( proj_code == PROJ_ALBERS_NAD83 ) THEN
349          IF ( .NOT.PRESENT(truelat1) .OR. &
350               .NOT.PRESENT(truelat2) .OR. &
351               .NOT.PRESENT(lat1) .OR. &
352               .NOT.PRESENT(lon1) .OR. &
353               .NOT.PRESENT(knowni) .OR. &
354               .NOT.PRESENT(knownj) .OR. &
355               .NOT.PRESENT(stdlon) .OR. &
356               .NOT.PRESENT(dx) ) THEN
357             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
358             PRINT '(A)', ' truelat1, truelat2, lat1, lon1, knonwi, knownj, stdlon, dx'
359             CALL wrf_error_fatal ( 'MAP_INIT' )
360          END IF
361       ELSE IF ( proj_code == PROJ_MERC ) THEN
362          IF ( .NOT.PRESENT(truelat1) .OR. &
363               .NOT.PRESENT(lat1) .OR. &
364               .NOT.PRESENT(lon1) .OR. &
365               .NOT.PRESENT(knowni) .OR. &
366               .NOT.PRESENT(knownj) .OR. &
367               .NOT.PRESENT(dx) ) THEN
368             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
369             PRINT '(A)', ' truelat1, lat1, lon1, knowni, knownj, dx'
370             CALL wrf_error_fatal ( 'MAP_INIT' )
371          END IF
372       ELSE IF ( proj_code == PROJ_LATLON ) THEN
373          IF ( .NOT.PRESENT(latinc) .OR. &
374               .NOT.PRESENT(loninc) .OR. &
375               .NOT.PRESENT(knowni) .OR. &
376               .NOT.PRESENT(knownj) .OR. &
377               .NOT.PRESENT(lat1) .OR. &
378               .NOT.PRESENT(lon1) ) THEN
379             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
380             PRINT '(A)', ' latinc, loninc, knowni, knownj, lat1, lon1'
381             CALL wrf_error_fatal ( 'MAP_INIT' )
382          END IF
383       ELSE IF ( proj_code == PROJ_CYL ) THEN
384          IF ( .NOT.PRESENT(latinc) .OR. &
385               .NOT.PRESENT(loninc) .OR. &
386               .NOT.PRESENT(stdlon) ) THEN
387             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
388             PRINT '(A)', ' latinc, loninc, stdlon'
389             CALL wrf_error_fatal ( 'MAP_INIT' )
390          END IF
391       ELSE IF ( proj_code == PROJ_CASSINI ) THEN
392          IF ( .NOT.PRESENT(latinc) .OR. &
393               .NOT.PRESENT(loninc) .OR. &
394               .NOT.PRESENT(lat1) .OR. &
395               .NOT.PRESENT(lon1) .OR. &
396               .NOT.PRESENT(lat0) .OR. &
397               .NOT.PRESENT(lon0) .OR. &
398               .NOT.PRESENT(knowni) .OR. &
399               .NOT.PRESENT(knownj) .OR. &
400               .NOT.PRESENT(stdlon) ) THEN
401             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
402             PRINT '(A)', ' latinc, loninc, lat1, lon1, knowni, knownj, lat0, lon0, stdlon'
403             CALL wrf_error_fatal ( 'MAP_INIT' )
404          END IF
405       ELSE IF ( proj_code == PROJ_GAUSS ) THEN
406          IF ( .NOT.PRESENT(nlat) .OR. &
407               .NOT.PRESENT(lat1) .OR. &
408               .NOT.PRESENT(lon1) .OR. &
409               .NOT.PRESENT(loninc) ) THEN
410             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
411             PRINT '(A)', ' nlat, lat1, lon1, loninc'
412             CALL wrf_error_fatal ( 'MAP_INIT' )
413          END IF
414       ELSE IF ( proj_code == PROJ_ROTLL ) THEN
415          IF ( .NOT.PRESENT(ixdim) .OR. &
416               .NOT.PRESENT(jydim) .OR. &
417               .NOT.PRESENT(phi) .OR. &
418               .NOT.PRESENT(lambda) .OR. &
419               .NOT.PRESENT(lat1) .OR. &
420               .NOT.PRESENT(lon1) .OR. &
421               .NOT.PRESENT(stagger) ) THEN
422             PRINT '(A,I2)', 'The following are mandatory parameters for projection code : ', proj_code
423             PRINT '(A)', ' ixdim, jydim, phi, lambda, lat1, lon1, stagger'
424             CALL wrf_error_fatal ( 'MAP_INIT' )
425          END IF
426       ELSE
427          PRINT '(A,I2)', 'Unknown projection code: ', proj_code
428          CALL wrf_error_fatal ( 'MAP_INIT' )
429       END IF
430   
431       ! Check for validity of mandatory variables in proj
432       IF ( PRESENT(lat1) ) THEN
433          IF ( ABS(lat1) .GT. 90. ) THEN
434             PRINT '(A)', 'Latitude of origin corner required as follows:'
435             PRINT '(A)', '    -90N <= lat1 < = 90.N'
436             CALL wrf_error_fatal ( 'MAP_INIT' )
437          ENDIF
438       ENDIF
439   
440       IF ( PRESENT(lon1) ) THEN
441          dummy_lon1 = lon1
442          IF ( ABS(dummy_lon1) .GT. 180.) THEN
443             iter = 0 
444             DO WHILE (ABS(dummy_lon1) > 180. .AND. iter < 10)
445                IF (dummy_lon1 < -180.) dummy_lon1 = dummy_lon1 + 360.
446                IF (dummy_lon1 > 180.) dummy_lon1 = dummy_lon1 - 360.
447                iter = iter + 1
448             END DO
449             IF (abs(dummy_lon1) > 180.) THEN
450                PRINT '(A)', 'Longitude of origin required as follows:'
451                PRINT '(A)', '   -180E <= lon1 <= 180W'
452                CALL wrf_error_fatal ( 'MAP_INIT' )
453             ENDIF
454          ENDIF
455       ENDIF
456   
457       IF ( PRESENT(lon0) ) THEN
458          dummy_lon0 = lon0
459          IF ( ABS(dummy_lon0) .GT. 180.) THEN
460             iter = 0 
461             DO WHILE (ABS(dummy_lon0) > 180. .AND. iter < 10)
462                IF (dummy_lon0 < -180.) dummy_lon0 = dummy_lon0 + 360.
463                IF (dummy_lon0 > 180.) dummy_lon0 = dummy_lon0 - 360.
464                iter = iter + 1
465             END DO
466             IF (abs(dummy_lon0) > 180.) THEN
467                PRINT '(A)', 'Longitude of pole required as follows:'
468                PRINT '(A)', '   -180E <= lon0 <= 180W'
469                CALL wrf_error_fatal ( 'MAP_INIT' )
470             ENDIF
471          ENDIF
472       ENDIF
473   
474       IF ( PRESENT(dx) ) THEN
475          IF ((dx .LE. 0.).AND.(proj_code .NE. PROJ_LATLON)) THEN
476             PRINT '(A)', 'Require grid spacing (dx) in meters be positive'
477             CALL wrf_error_fatal ( 'MAP_INIT' )
478          ENDIF
479       ENDIF
480   
481       IF ( PRESENT(stdlon) ) THEN
482          dummy_stdlon = stdlon
483          IF ((ABS(dummy_stdlon) > 180.).AND.(proj_code /= PROJ_MERC)) THEN
484             iter = 0 
485             DO WHILE (ABS(dummy_stdlon) > 180. .AND. iter < 10)
486                IF (dummy_stdlon < -180.) dummy_stdlon = dummy_stdlon + 360.
487                IF (dummy_stdlon > 180.) dummy_stdlon = dummy_stdlon - 360.
488                iter = iter + 1
489             END DO
490             IF (abs(dummy_stdlon) > 180.) THEN
491                PRINT '(A)', 'Need orientation longitude (stdlon) as: '
492                PRINT '(A)', '   -180E <= stdlon <= 180W' 
493                CALL wrf_error_fatal ( 'MAP_INIT' )
494             ENDIF
495          ENDIF
496       ENDIF
497   
498       IF ( PRESENT(truelat1) ) THEN
499          IF (ABS(truelat1).GT.90.) THEN
500             PRINT '(A)', 'Set true latitude 1 for all projections'
501             CALL wrf_error_fatal ( 'MAP_INIT' )
502          ENDIF
503       ENDIF
504      
505       CALL map_init(proj) 
506       proj%code  = proj_code
507       IF ( PRESENT(lat1) )     proj%lat1     = lat1
508       IF ( PRESENT(lon1) )     proj%lon1     = dummy_lon1
509       IF ( PRESENT(lat0) )     proj%lat0     = lat0
510       IF ( PRESENT(lon0) )     proj%lon0     = dummy_lon0
511       IF ( PRESENT(latinc) )   proj%latinc   = latinc
512       IF ( PRESENT(loninc) )   proj%loninc   = loninc
513       IF ( PRESENT(knowni) )   proj%knowni   = knowni
514       IF ( PRESENT(knownj) )   proj%knownj   = knownj
515       IF ( PRESENT(dx) )       proj%dx       = dx
516       IF ( PRESENT(stdlon) )   proj%stdlon   = dummy_stdlon
517       IF ( PRESENT(truelat1) ) proj%truelat1 = truelat1
518       IF ( PRESENT(truelat2) ) proj%truelat2 = truelat2
519       IF ( PRESENT(nlat) )     proj%nlat     = nlat
520       IF ( PRESENT(nlon) )     proj%nlon     = nlon
521       IF ( PRESENT(ixdim) )    proj%ixdim    = ixdim
522       IF ( PRESENT(jydim) )    proj%jydim    = jydim
523       IF ( PRESENT(stagger) )  proj%stagger  = stagger
524       IF ( PRESENT(phi) )      proj%phi      = phi
525       IF ( PRESENT(lambda) )   proj%lambda   = lambda
526       IF ( PRESENT(r_earth) )  proj%re_m     = r_earth
527   
528       IF ( PRESENT(dx) ) THEN 
529          IF ( (proj_code == PROJ_LC) .OR. (proj_code == PROJ_PS) .OR. &
530               (proj_code == PROJ_PS_WGS84) .OR. (proj_code == PROJ_ALBERS_NAD83) .OR. &
531               (proj_code == PROJ_MERC) ) THEN
532             proj%dx = dx
533             IF (truelat1 .LT. 0.) THEN
534                proj%hemi = -1.0 
535             ELSE
536                proj%hemi = 1.0
537             ENDIF
538             proj%rebydx = proj%re_m / dx
539          ENDIF
540       ENDIF
542       pick_proj: SELECT CASE(proj%code)
543   
544          CASE(PROJ_PS)
545             CALL set_ps(proj)
547          CASE(PROJ_PS_WGS84)
548             CALL set_ps_wgs84(proj)
550          CASE(PROJ_ALBERS_NAD83)
551             CALL set_albers_nad83(proj)
552    
553          CASE(PROJ_LC)
554             IF (ABS(proj%truelat2) .GT. 90.) THEN
555                proj%truelat2=proj%truelat1
556             ENDIF
557             CALL set_lc(proj)
558       
559          CASE (PROJ_MERC)
560             CALL set_merc(proj)
561       
562          CASE (PROJ_LATLON)
563    
564          CASE (PROJ_GAUSS)
565             CALL set_gauss(proj)
566       
567          CASE (PROJ_CYL)
568             CALL set_cyl(proj)
569       
570          CASE (PROJ_CASSINI)
571             CALL set_cassini(proj)
572       
573          CASE (PROJ_ROTLL)
574      
575       END SELECT pick_proj
576       proj%init = .TRUE.
578       RETURN
580    END SUBROUTINE map_set
583    SUBROUTINE latlon_to_ij(proj, lat, lon, i, j)
584       ! Converts input lat/lon values to the cartesian (i,j) value
585       ! for the given projection. 
586   
587       IMPLICIT NONE
588       TYPE(proj_info), INTENT(IN)          :: proj
589       REAL, INTENT(IN)                     :: lat
590       REAL, INTENT(IN)                     :: lon
591       REAL, INTENT(OUT)                    :: i
592       REAL, INTENT(OUT)                    :: j
593   
594       IF (.NOT.proj%init) THEN
595          PRINT '(A)', 'You have not called map_set for this projection'
596          CALL wrf_error_fatal ( 'LATLON_TO_IJ' )
597       ENDIF
598   
599       SELECT CASE(proj%code)
600    
601          CASE(PROJ_LATLON)
602             CALL llij_latlon(lat,lon,proj,i,j)
603    
604          CASE(PROJ_MERC)
605             CALL llij_merc(lat,lon,proj,i,j)
606    
607          CASE(PROJ_PS)
608             CALL llij_ps(lat,lon,proj,i,j)
610          CASE(PROJ_PS_WGS84)
611             CALL llij_ps_wgs84(lat,lon,proj,i,j)
612          
613          CASE(PROJ_ALBERS_NAD83)
614             CALL llij_albers_nad83(lat,lon,proj,i,j)
615          
616          CASE(PROJ_LC)
617             CALL llij_lc(lat,lon,proj,i,j)
618    
619          CASE(PROJ_GAUSS)
620             CALL llij_gauss(lat,lon,proj,i,j)
621    
622          CASE(PROJ_CYL)
623             CALL llij_cyl(lat,lon,proj,i,j)
625          CASE(PROJ_CASSINI)
626             CALL llij_cassini(lat,lon,proj,i,j)
628          CASE(PROJ_ROTLL)
629             CALL llij_rotlatlon(lat,lon,proj,i,j)
630    
631          CASE DEFAULT
632             PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code
633             CALL wrf_error_fatal ( 'LATLON_TO_IJ' )
634     
635       END SELECT
637       RETURN
639    END SUBROUTINE latlon_to_ij
642    SUBROUTINE ij_to_latlon(proj, i, j, lat, lon)
643       ! Computes geographical latitude and longitude for a given (i,j) point
644       ! in a grid with a projection of proj
645   
646       IMPLICIT NONE
647       TYPE(proj_info),INTENT(IN)          :: proj
648       REAL, INTENT(IN)                    :: i
649       REAL, INTENT(IN)                    :: j
650       REAL, INTENT(OUT)                   :: lat
651       REAL, INTENT(OUT)                   :: lon
652   
653       IF (.NOT.proj%init) THEN
654          PRINT '(A)', 'You have not called map_set for this projection'
655          CALL wrf_error_fatal ( 'IJ_TO_LATLON' )
656       ENDIF
657       SELECT CASE (proj%code)
658   
659          CASE (PROJ_LATLON)
660             CALL ijll_latlon(i, j, proj, lat, lon)
661    
662          CASE (PROJ_MERC)
663             CALL ijll_merc(i, j, proj, lat, lon)
664    
665          CASE (PROJ_PS)
666             CALL ijll_ps(i, j, proj, lat, lon)
668          CASE (PROJ_PS_WGS84)
669             CALL ijll_ps_wgs84(i, j, proj, lat, lon)
670    
671          CASE (PROJ_ALBERS_NAD83)
672             CALL ijll_albers_nad83(i, j, proj, lat, lon)
673    
674          CASE (PROJ_LC)
675             CALL ijll_lc(i, j, proj, lat, lon)
676    
677          CASE (PROJ_CYL)
678             CALL ijll_cyl(i, j, proj, lat, lon)
679    
680          CASE (PROJ_CASSINI)
681             CALL ijll_cassini(i, j, proj, lat, lon)
682    
683          CASE (PROJ_ROTLL)
684             CALL ijll_rotlatlon(i, j, proj, lat, lon)
685    
686          CASE DEFAULT
687             PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code
688             CALL wrf_error_fatal ( 'IJ_TO_LATLON' )
689   
690       END SELECT
691       RETURN
692    END SUBROUTINE ij_to_latlon
695    SUBROUTINE set_ps(proj)
696       ! Initializes a polar-stereographic map projection from the partially
697       ! filled proj structure. This routine computes the radius to the
698       ! southwest corner and computes the i/j location of the pole for use
699       ! in llij_ps and ijll_ps.
700       IMPLICIT NONE
701    
702       ! Declare args
703       TYPE(proj_info), INTENT(INOUT)    :: proj
704   
705       ! Local vars
706       REAL                              :: ala1
707       REAL                              :: alo1
708       REAL                              :: reflon
709       REAL                              :: scale_top
710   
711       ! Executable code
712       reflon = proj%stdlon + 90.
713   
714       ! Compute numerator term of map scale factor
715       scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
716   
717       ! Compute radius to lower-left (SW) corner
718       ala1 = proj%lat1 * rad_per_deg
719       proj%rsw = proj%rebydx*COS(ala1)*scale_top/(1.+proj%hemi*SIN(ala1))
720   
721       ! Find the pole point
722       alo1 = (proj%lon1 - reflon) * rad_per_deg
723       proj%polei = proj%knowni - proj%rsw * COS(alo1)
724       proj%polej = proj%knownj - proj%hemi * proj%rsw * SIN(alo1)
726       RETURN
728    END SUBROUTINE set_ps
731    SUBROUTINE llij_ps(lat,lon,proj,i,j)
732       ! Given latitude (-90 to 90), longitude (-180 to 180), and the
733       ! standard polar-stereographic projection information via the 
734       ! public proj structure, this routine returns the i/j indices which
735       ! if within the domain range from 1->nx and 1->ny, respectively.
736   
737       IMPLICIT NONE
738   
739       ! Delcare input arguments
740       REAL, INTENT(IN)               :: lat
741       REAL, INTENT(IN)               :: lon
742       TYPE(proj_info),INTENT(IN)     :: proj
743   
744       ! Declare output arguments     
745       REAL, INTENT(OUT)              :: i !(x-index)
746       REAL, INTENT(OUT)              :: j !(y-index)
747   
748       ! Declare local variables
749       
750       REAL                           :: reflon
751       REAL                           :: scale_top
752       REAL                           :: ala
753       REAL                           :: alo
754       REAL                           :: rm
755   
756       ! BEGIN CODE
757     
758       reflon = proj%stdlon + 90.
759      
760       ! Compute numerator term of map scale factor
761   
762       scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
763   
764       ! Find radius to desired point
765       ala = lat * rad_per_deg
766       rm = proj%rebydx * COS(ala) * scale_top/(1. + proj%hemi *SIN(ala))
767       alo = (lon - reflon) * rad_per_deg
768       i = proj%polei + rm * COS(alo)
769       j = proj%polej + proj%hemi * rm * SIN(alo)
770    
771       RETURN
773    END SUBROUTINE llij_ps
776    SUBROUTINE ijll_ps(i, j, proj, lat, lon)
778       ! This is the inverse subroutine of llij_ps.  It returns the 
779       ! latitude and longitude of an i/j point given the projection info 
780       ! structure.  
781   
782       IMPLICIT NONE
783   
784       ! Declare input arguments
785       REAL, INTENT(IN)                    :: i    ! Column
786       REAL, INTENT(IN)                    :: j    ! Row
787       TYPE (proj_info), INTENT(IN)        :: proj
788       
789       ! Declare output arguments
790       REAL, INTENT(OUT)                   :: lat     ! -90 -> 90 north
791       REAL, INTENT(OUT)                   :: lon     ! -180 -> 180 East
792   
793       ! Local variables
794       REAL                                :: reflon
795       REAL                                :: scale_top
796       REAL                                :: xx,yy
797       REAL                                :: gi2, r2
798       REAL                                :: arccos
799   
800       ! Begin Code
801   
802       ! Compute the reference longitude by rotating 90 degrees to the east
803       ! to find the longitude line parallel to the positive x-axis.
804       reflon = proj%stdlon + 90.
805      
806       ! Compute numerator term of map scale factor
807       scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg)
808   
809       ! Compute radius to point of interest
810       xx = i - proj%polei
811       yy = (j - proj%polej) * proj%hemi
812       r2 = xx**2 + yy**2
813   
814       ! Now the magic code
815       IF (r2 .EQ. 0.) THEN 
816          lat = proj%hemi * 90.
817          lon = reflon
818       ELSE
819          gi2 = (proj%rebydx * scale_top)**2.
820          lat = deg_per_rad * proj%hemi * ASIN((gi2-r2)/(gi2+r2))
821          arccos = ACOS(xx/SQRT(r2))
822          IF (yy .GT. 0) THEN
823             lon = reflon + deg_per_rad * arccos
824          ELSE
825             lon = reflon - deg_per_rad * arccos
826          ENDIF
827       ENDIF
828     
829       ! Convert to a -180 -> 180 East convention
830       IF (lon .GT. 180.) lon = lon - 360.
831       IF (lon .LT. -180.) lon = lon + 360.
833       RETURN
834    
835    END SUBROUTINE ijll_ps
838    SUBROUTINE set_ps_wgs84(proj)
839       ! Initializes a polar-stereographic map projection (WGS84 ellipsoid) 
840       ! from the partially filled proj structure. This routine computes the 
841       ! radius to the southwest corner and computes the i/j location of the 
842       ! pole for use in llij_ps and ijll_ps.
844       IMPLICIT NONE
845    
846       ! Arguments
847       TYPE(proj_info), INTENT(INOUT)    :: proj
848   
849       ! Local variables
850       real :: h, mc, tc, t, rho
852       h = proj%hemi
854       mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
855       tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg)))* &
856                 (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
858       ! Find the i/j location of reference lat/lon with respect to the pole of the projection
859       t = sqrt(((1.0-sin(h*proj%lat1*rad_per_deg))/(1.0+sin(h*proj%lat1*rad_per_deg)))* &
860                (((1.0+E_WGS84*sin(h*proj%lat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%lat1*rad_per_deg)) )**E_WGS84 ) )
861       rho = h * (A_WGS84 / proj%dx) * mc * t / tc
862       proj%polei = rho * sin((h*proj%lon1 - h*proj%stdlon)*rad_per_deg)
863       proj%polej = -rho * cos((h*proj%lon1 - h*proj%stdlon)*rad_per_deg)
865       RETURN
867    END SUBROUTINE set_ps_wgs84
870    SUBROUTINE llij_ps_wgs84(lat,lon,proj,i,j)
871       ! Given latitude (-90 to 90), longitude (-180 to 180), and the
872       ! standard polar-stereographic projection information via the 
873       ! public proj structure, this routine returns the i/j indices which
874       ! if within the domain range from 1->nx and 1->ny, respectively.
875   
876       IMPLICIT NONE
877   
878       ! Arguments
879       REAL, INTENT(IN)               :: lat
880       REAL, INTENT(IN)               :: lon
881       REAL, INTENT(OUT)              :: i !(x-index)
882       REAL, INTENT(OUT)              :: j !(y-index)
883       TYPE(proj_info),INTENT(IN)     :: proj
884   
885       ! Local variables
886       real :: h, mc, tc, t, rho
888       h = proj%hemi
890       mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
891       tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg)))* &
892                 (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
894       t = sqrt(((1.0-sin(h*lat*rad_per_deg))/(1.0+sin(h*lat*rad_per_deg))) * &
895                (((1.0+E_WGS84*sin(h*lat*rad_per_deg))/(1.0-E_WGS84*sin(h*lat*rad_per_deg)))**E_WGS84))
897       ! Find the x/y location of the requested lat/lon with respect to the pole of the projection
898       rho = (A_WGS84 / proj%dx) * mc * t / tc
899       i = h *  rho * sin((h*lon - h*proj%stdlon)*rad_per_deg)
900       j = h *(-rho)* cos((h*lon - h*proj%stdlon)*rad_per_deg)
902       ! Get i/j relative to reference i/j
903       i = proj%knowni + (i - proj%polei)
904       j = proj%knownj + (j - proj%polej)
905   
906       RETURN
908    END SUBROUTINE llij_ps_wgs84
911    SUBROUTINE ijll_ps_wgs84(i, j, proj, lat, lon)
913       ! This is the inverse subroutine of llij_ps.  It returns the 
914       ! latitude and longitude of an i/j point given the projection info 
915       ! structure.  
916   
917       implicit none
918   
919       ! Arguments
920       REAL, INTENT(IN)                    :: i    ! Column
921       REAL, INTENT(IN)                    :: j    ! Row
922       REAL, INTENT(OUT)                   :: lat     ! -90 -> 90 north
923       REAL, INTENT(OUT)                   :: lon     ! -180 -> 180 East
924       TYPE (proj_info), INTENT(IN)        :: proj
926       ! Local variables
927       real :: h, mc, tc, t, rho, x, y
928       real :: chi, a, b, c, d
930       h = proj%hemi
931       x = (i - proj%knowni + proj%polei)
932       y = (j - proj%knownj + proj%polej)
934       mc = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_WGS84*sin(h*proj%truelat1*rad_per_deg))**2.0)
935       tc = sqrt(((1.0-sin(h*proj%truelat1*rad_per_deg))/(1.0+sin(h*proj%truelat1*rad_per_deg))) * &
936                 (((1.0+E_WGS84*sin(h*proj%truelat1*rad_per_deg))/(1.0-E_WGS84*sin(h*proj%truelat1*rad_per_deg)))**E_WGS84 ))
938       rho = sqrt((x*proj%dx)**2.0 + (y*proj%dx)**2.0)
939       t = rho * tc / (A_WGS84 * mc) 
941       lon = h*proj%stdlon + h*atan2(h*x,h*(-y))
943       chi = PI/2.0-2.0*atan(t)
944       a = 1./2.*E_WGS84**2. + 5./24.*E_WGS84**4. +  1./40.*E_WGS84**6.  +    73./2016.*E_WGS84**8.
945       b =                     7./24.*E_WGS84**4. + 29./120.*E_WGS84**6. + 54113./40320.*E_WGS84**8.
946       c =                                           7./30.*E_WGS84**6.  +    81./280.*E_WGS84**8.
947       d =                                                                  4279./20160.*E_WGS84**8.
949       lat = chi + sin(2.*chi)*(a + cos(2.*chi)*(b + cos(2.*chi)*(c + d*cos(2.*chi))))
950       lat = h * lat
952       lat = lat*deg_per_rad
953       lon = lon*deg_per_rad
955       RETURN
956    
957    END SUBROUTINE ijll_ps_wgs84
960    SUBROUTINE set_albers_nad83(proj)
961       ! Initializes an Albers equal area map projection (NAD83 ellipsoid) 
962       ! from the partially filled proj structure. This routine computes the 
963       ! radius to the southwest corner and computes the i/j location of the 
964       ! pole for use in llij_albers_nad83 and ijll_albers_nad83.
966       IMPLICIT NONE
967    
968       ! Arguments
969       TYPE(proj_info), INTENT(INOUT)    :: proj
970   
971       ! Local variables
972       real :: h, m1, m2, q1, q2, theta, q, sinphi
974       h = proj%hemi
976       m1 = cos(h*proj%truelat1*rad_per_deg)/sqrt(1.0-(E_NAD83*sin(h*proj%truelat1*rad_per_deg))**2.0)
977       m2 = cos(h*proj%truelat2*rad_per_deg)/sqrt(1.0-(E_NAD83*sin(h*proj%truelat2*rad_per_deg))**2.0)
979       sinphi = sin(proj%truelat1*rad_per_deg)
980       q1 = (1.0-E_NAD83**2.0) * &
981            ((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)))
983       sinphi = sin(proj%truelat2*rad_per_deg)
984       q2 = (1.0-E_NAD83**2.0) * &
985            ((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)))
987       if (proj%truelat1 == proj%truelat2) then
988          proj%nc = sin(proj%truelat1*rad_per_deg)
989       else
990          proj%nc = (m1**2.0 - m2**2.0) / (q2 - q1)
991       end if
993       proj%bigc = m1**2.0 + proj%nc*q1
995       ! Find the i/j location of reference lat/lon with respect to the pole of the projection
996       sinphi = sin(proj%lat1*rad_per_deg)
997       q = (1.0-E_NAD83**2.0) * &
998            ((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)))
1000       proj%rho0 = h * (A_NAD83 / proj%dx) * sqrt(proj%bigc - proj%nc * q) / proj%nc 
1001       theta = proj%nc*(proj%lon1 - proj%stdlon)*rad_per_deg
1003       proj%polei = proj%rho0 * sin(h*theta) 
1004       proj%polej = proj%rho0 - proj%rho0 * cos(h*theta)
1006       RETURN
1008    END SUBROUTINE set_albers_nad83
1011    SUBROUTINE llij_albers_nad83(lat,lon,proj,i,j)
1012       ! Given latitude (-90 to 90), longitude (-180 to 180), and the
1013       ! standard projection information via the 
1014       ! public proj structure, this routine returns the i/j indices which
1015       ! if within the domain range from 1->nx and 1->ny, respectively.
1016   
1017       IMPLICIT NONE
1018   
1019       ! Arguments
1020       REAL, INTENT(IN)               :: lat
1021       REAL, INTENT(IN)               :: lon
1022       REAL, INTENT(OUT)              :: i !(x-index)
1023       REAL, INTENT(OUT)              :: j !(y-index)
1024       TYPE(proj_info),INTENT(IN)     :: proj
1025   
1026       ! Local variables
1027       real :: h, q, rho, theta, sinphi
1029       h = proj%hemi
1031       sinphi = sin(h*lat*rad_per_deg)
1033       ! Find the x/y location of the requested lat/lon with respect to the pole of the projection
1034       q = (1.0-E_NAD83**2.0) * &
1035            ((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)))
1037       rho = h * (A_NAD83 / proj%dx) * sqrt(proj%bigc - proj%nc * q) / proj%nc
1038       theta = proj%nc * (h*lon - h*proj%stdlon)*rad_per_deg
1040       i = h*rho*sin(theta)
1041       j = h*proj%rho0 - h*rho*cos(theta)
1043       ! Get i/j relative to reference i/j
1044       i = proj%knowni + (i - proj%polei)
1045       j = proj%knownj + (j - proj%polej)
1047       RETURN
1049    END SUBROUTINE llij_albers_nad83
1052    SUBROUTINE ijll_albers_nad83(i, j, proj, lat, lon)
1054       ! This is the inverse subroutine of llij_albers_nad83.  It returns the 
1055       ! latitude and longitude of an i/j point given the projection info 
1056       ! structure.  
1057   
1058       implicit none
1059   
1060       ! Arguments
1061       REAL, INTENT(IN)                    :: i    ! Column
1062       REAL, INTENT(IN)                    :: j    ! Row
1063       REAL, INTENT(OUT)                   :: lat     ! -90 -> 90 north
1064       REAL, INTENT(OUT)                   :: lon     ! -180 -> 180 East
1065       TYPE (proj_info), INTENT(IN)        :: proj
1067       ! Local variables
1068       real :: h, q, rho, theta, beta, x, y
1069       real :: a, b, c
1071       h = proj%hemi
1073       x = (i - proj%knowni + proj%polei)
1074       y = (j - proj%knownj + proj%polej)
1076       rho = sqrt(x**2.0 + (proj%rho0 - y)**2.0)
1077       theta = atan2(x, proj%rho0-y)
1079       q = (proj%bigc - (rho*proj%nc*proj%dx/A_NAD83)**2.0) / proj%nc
1081       beta = asin(q/(1.0 - log((1.0-E_NAD83)/(1.0+E_NAD83))*(1.0-E_NAD83**2.0)/(2.0*E_NAD83)))
1082       a = 1./3.*E_NAD83**2. + 31./180.*E_NAD83**4. + 517./5040.*E_NAD83**6.
1083       b =                     23./360.*E_NAD83**4. + 251./3780.*E_NAD83**6.
1084       c =                                            761./45360.*E_NAD83**6.
1086       lat = beta + a*sin(2.*beta) + b*sin(4.*beta) + c*sin(6.*beta)
1088       lat = h*lat*deg_per_rad
1089       lon = proj%stdlon + theta*deg_per_rad/proj%nc
1091       RETURN
1092    
1093    END SUBROUTINE ijll_albers_nad83
1096    SUBROUTINE set_lc(proj)
1097       ! Initialize the remaining items in the proj structure for a
1098       ! lambert conformal grid.
1099   
1100       IMPLICIT NONE
1101       
1102       TYPE(proj_info), INTENT(INOUT)     :: proj
1103   
1104       REAL                               :: arg
1105       REAL                               :: deltalon1
1106       REAL                               :: tl1r
1107       REAL                               :: ctl1r
1108   
1109       ! Compute cone factor
1110       CALL lc_cone(proj%truelat1, proj%truelat2, proj%cone)
1111   
1112       ! Compute longitude differences and ensure we stay out of the
1113       ! forbidden "cut zone"
1114       deltalon1 = proj%lon1 - proj%stdlon
1115       IF (deltalon1 .GT. +180.) deltalon1 = deltalon1 - 360.
1116       IF (deltalon1 .LT. -180.) deltalon1 = deltalon1 + 360.
1117   
1118       ! Convert truelat1 to radian and compute COS for later use
1119       tl1r = proj%truelat1 * rad_per_deg
1120       ctl1r = COS(tl1r)
1121   
1122       ! Compute the radius to our known lower-left (SW) corner
1123       proj%rsw = proj%rebydx * ctl1r/proj%cone * &
1124              (TAN((90.*proj%hemi-proj%lat1)*rad_per_deg/2.) / &
1125               TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone
1126   
1127       ! Find pole point
1128       arg = proj%cone*(deltalon1*rad_per_deg)
1129       proj%polei = proj%hemi*proj%knowni - proj%hemi * proj%rsw * SIN(arg)
1130       proj%polej = proj%hemi*proj%knownj + proj%rsw * COS(arg)  
1131   
1132       RETURN
1134    END SUBROUTINE set_lc                             
1137    SUBROUTINE lc_cone(truelat1, truelat2, cone)
1139    ! Subroutine to compute the cone factor of a Lambert Conformal projection
1141       IMPLICIT NONE
1142       
1143       ! Input Args
1144       REAL, INTENT(IN)             :: truelat1  ! (-90 -> 90 degrees N)
1145       REAL, INTENT(IN)             :: truelat2  !   "   "  "   "     "
1146   
1147       ! Output Args
1148       REAL, INTENT(OUT)            :: cone
1149   
1150       ! Locals
1151   
1152       ! BEGIN CODE
1153   
1154       ! First, see if this is a secant or tangent projection.  For tangent
1155       ! projections, truelat1 = truelat2 and the cone is tangent to the 
1156       ! Earth's surface at this latitude.  For secant projections, the cone
1157       ! intersects the Earth's surface at each of the distinctly different
1158       ! latitudes
1159       IF (ABS(truelat1-truelat2) .GT. 0.1) THEN
1160          cone = ALOG10(COS(truelat1*rad_per_deg)) - &
1161                 ALOG10(COS(truelat2*rad_per_deg))
1162          cone = cone /(ALOG10(TAN((45.0 - ABS(truelat1)/2.0) * rad_per_deg)) - &
1163                 ALOG10(TAN((45.0 - ABS(truelat2)/2.0) * rad_per_deg)))        
1164       ELSE
1165          cone = SIN(ABS(truelat1)*rad_per_deg )  
1166       ENDIF
1168       RETURN
1170    END SUBROUTINE lc_cone
1173    SUBROUTINE ijll_lc( i, j, proj, lat, lon)
1175    ! Subroutine to convert from the (i,j) cartesian coordinate to the 
1176    ! geographical latitude and longitude for a Lambert Conformal projection.
1178    ! History:
1179    ! 25 Jul 01: Corrected by B. Shaw, NOAA/FSL
1180    ! 
1181       IMPLICIT NONE
1182   
1183       ! Input Args
1184       REAL, INTENT(IN)              :: i        ! Cartesian X coordinate
1185       REAL, INTENT(IN)              :: j        ! Cartesian Y coordinate
1186       TYPE(proj_info),INTENT(IN)    :: proj     ! Projection info structure
1187   
1188       ! Output Args                 
1189       REAL, INTENT(OUT)             :: lat      ! Latitude (-90->90 deg N)
1190       REAL, INTENT(OUT)             :: lon      ! Longitude (-180->180 E)
1191   
1192       ! Locals 
1193       REAL                          :: inew
1194       REAL                          :: jnew
1195       REAL                          :: r
1196       REAL                          :: chi,chi1,chi2
1197       REAL                          :: r2
1198       REAL                          :: xx
1199       REAL                          :: yy
1200   
1201       ! BEGIN CODE
1202   
1203       chi1 = (90. - proj%hemi*proj%truelat1)*rad_per_deg
1204       chi2 = (90. - proj%hemi*proj%truelat2)*rad_per_deg
1205   
1206       ! See if we are in the southern hemispere and flip the indices
1207       ! if we are. 
1208       inew = proj%hemi * i
1209       jnew = proj%hemi * j
1210   
1211       ! Compute radius**2 to i/j location
1212       xx = inew - proj%polei
1213       yy = proj%polej - jnew
1214       r2 = (xx*xx + yy*yy)
1215       r = SQRT(r2)/proj%rebydx
1216      
1217       ! Convert to lat/lon
1218       IF (r2 .EQ. 0.) THEN
1219          lat = proj%hemi * 90.
1220          lon = proj%stdlon
1221       ELSE
1222          
1223          ! Longitude
1224          lon = proj%stdlon + deg_per_rad * ATAN2(proj%hemi*xx,yy)/proj%cone
1225          lon = MOD(lon+360., 360.)
1226    
1227          ! Latitude.  Latitude determined by solving an equation adapted 
1228          ! from:
1229          !  Maling, D.H., 1973: Coordinate Systems and Map Projections
1230          ! Equations #20 in Appendix I.  
1231            
1232          IF (chi1 .EQ. chi2) THEN
1233             chi = 2.0*ATAN( ( r/TAN(chi1) )**(1./proj%cone) * TAN(chi1*0.5) )
1234          ELSE
1235             chi = 2.0*ATAN( (r*proj%cone/SIN(chi1))**(1./proj%cone) * TAN(chi1*0.5)) 
1236          ENDIF
1237          lat = (90.0-chi*deg_per_rad)*proj%hemi
1238   
1239       ENDIF
1240   
1241       IF (lon .GT. +180.) lon = lon - 360.
1242       IF (lon .LT. -180.) lon = lon + 360.
1244       RETURN
1246    END SUBROUTINE ijll_lc
1249    SUBROUTINE llij_lc( lat, lon, proj, i, j)
1251    ! Subroutine to compute the geographical latitude and longitude values
1252    ! to the cartesian x/y on a Lambert Conformal projection.
1253      
1254       IMPLICIT NONE
1255   
1256       ! Input Args
1257       REAL, INTENT(IN)              :: lat      ! Latitude (-90->90 deg N)
1258       REAL, INTENT(IN)              :: lon      ! Longitude (-180->180 E)
1259       TYPE(proj_info),INTENT(IN)      :: proj     ! Projection info structure
1260   
1261       ! Output Args                 
1262       REAL, INTENT(OUT)             :: i        ! Cartesian X coordinate
1263       REAL, INTENT(OUT)             :: j        ! Cartesian Y coordinate
1264   
1265       ! Locals 
1266       REAL                          :: arg
1267       REAL                          :: deltalon
1268       REAL                          :: tl1r
1269       REAL                          :: rm
1270       REAL                          :: ctl1r
1271       
1272   
1273       ! BEGIN CODE
1274       
1275       ! Compute deltalon between known longitude and standard lon and ensure
1276       ! it is not in the cut zone
1277       deltalon = lon - proj%stdlon
1278       IF (deltalon .GT. +180.) deltalon = deltalon - 360.
1279       IF (deltalon .LT. -180.) deltalon = deltalon + 360.
1280       
1281       ! Convert truelat1 to radian and compute COS for later use
1282       tl1r = proj%truelat1 * rad_per_deg
1283       ctl1r = COS(tl1r)     
1284      
1285       ! Radius to desired point
1286       rm = proj%rebydx * ctl1r/proj%cone * &
1287            (TAN((90.*proj%hemi-lat)*rad_per_deg/2.) / &
1288             TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone
1289   
1290       arg = proj%cone*(deltalon*rad_per_deg)
1291       i = proj%polei + proj%hemi * rm * SIN(arg)
1292       j = proj%polej - rm * COS(arg)
1293   
1294       ! Finally, if we are in the southern hemisphere, flip the i/j
1295       ! values to a coordinate system where (1,1) is the SW corner
1296       ! (what we assume) which is different than the original NCEP
1297       ! algorithms which used the NE corner as the origin in the 
1298       ! southern hemisphere (left-hand vs. right-hand coordinate?)
1299       i = proj%hemi * i  
1300       j = proj%hemi * j
1302       RETURN
1303    END SUBROUTINE llij_lc
1306    SUBROUTINE set_merc(proj)
1307    
1308       ! Sets up the remaining basic elements for the mercator projection
1309   
1310       IMPLICIT NONE
1311       TYPE(proj_info), INTENT(INOUT)       :: proj
1312       REAL                                 :: clain
1313   
1314   
1315       !  Preliminary variables
1316   
1317       clain = COS(rad_per_deg*proj%truelat1)
1318       proj%dlon = proj%dx / (proj%re_m * clain)
1319   
1320       ! Compute distance from equator to origin, and store in the 
1321       ! proj%rsw tag.
1322   
1323       proj%rsw = 0.
1324       IF (proj%lat1 .NE. 0.) THEN
1325          proj%rsw = (ALOG(TAN(0.5*((proj%lat1+90.)*rad_per_deg))))/proj%dlon
1326       ENDIF
1328       RETURN
1330    END SUBROUTINE set_merc
1333    SUBROUTINE llij_merc(lat, lon, proj, i, j)
1335       ! Compute i/j coordinate from lat lon for mercator projection
1336     
1337       IMPLICIT NONE
1338       REAL, INTENT(IN)              :: lat
1339       REAL, INTENT(IN)              :: lon
1340       TYPE(proj_info),INTENT(IN)    :: proj
1341       REAL,INTENT(OUT)              :: i
1342       REAL,INTENT(OUT)              :: j
1343       REAL                          :: deltalon
1344   
1345       deltalon = lon - proj%lon1
1346       IF (deltalon .LT. -180.) deltalon = deltalon + 360.
1347       IF (deltalon .GT. 180.) deltalon = deltalon - 360.
1348       i = proj%knowni + (deltalon/(proj%dlon*deg_per_rad))
1349       j = proj%knownj + (ALOG(TAN(0.5*((lat + 90.) * rad_per_deg)))) / &
1350              proj%dlon - proj%rsw
1351   
1352       RETURN
1354    END SUBROUTINE llij_merc
1357    SUBROUTINE ijll_merc(i, j, proj, lat, lon)
1359       ! Compute the lat/lon from i/j for mercator projection
1360   
1361       IMPLICIT NONE
1362       REAL,INTENT(IN)               :: i
1363       REAL,INTENT(IN)               :: j    
1364       TYPE(proj_info),INTENT(IN)    :: proj
1365       REAL, INTENT(OUT)             :: lat
1366       REAL, INTENT(OUT)             :: lon 
1367   
1368   
1369       lat = 2.0*ATAN(EXP(proj%dlon*(proj%rsw + j-proj%knownj)))*deg_per_rad - 90.
1370       lon = (i-proj%knowni)*proj%dlon*deg_per_rad + proj%lon1
1371       IF (lon.GT.180.) lon = lon - 360.
1372       IF (lon.LT.-180.) lon = lon + 360.
1373       RETURN
1375    END SUBROUTINE ijll_merc
1378    SUBROUTINE llij_latlon(lat, lon, proj, i, j)
1379   
1380       ! Compute the i/j location of a lat/lon on a LATLON grid.
1381       IMPLICIT NONE
1382       REAL, INTENT(IN)             :: lat
1383       REAL, INTENT(IN)             :: lon
1384       TYPE(proj_info), INTENT(IN)  :: proj
1385       REAL, INTENT(OUT)            :: i
1386       REAL, INTENT(OUT)            :: j
1387   
1388       REAL                         :: deltalat
1389       REAL                         :: deltalon
1390   
1391       ! Compute deltalat and deltalon as the difference between the input 
1392       ! lat/lon and the origin lat/lon
1393       deltalat = lat - proj%lat1
1394       deltalon = lon - proj%lon1      
1395       
1396       ! Compute i/j
1397       i = deltalon/proj%loninc
1398       j = deltalat/proj%latinc
1400       i = i + proj%knowni
1401       j = j + proj%knownj
1402   
1403       RETURN
1405    END SUBROUTINE llij_latlon
1408    SUBROUTINE ijll_latlon(i, j, proj, lat, lon)
1409   
1410       ! Compute the lat/lon location of an i/j on a LATLON grid.
1411       IMPLICIT NONE
1412       REAL, INTENT(IN)             :: i
1413       REAL, INTENT(IN)             :: j
1414       TYPE(proj_info), INTENT(IN)  :: proj
1415       REAL, INTENT(OUT)            :: lat
1416       REAL, INTENT(OUT)            :: lon
1417   
1418       REAL                         :: i_work, j_work
1419       REAL                         :: deltalat
1420       REAL                         :: deltalon
1421   
1422       i_work = i - proj%knowni
1423       j_work = j - proj%knownj
1425       ! Compute deltalat and deltalon 
1426       deltalat = j_work*proj%latinc
1427       deltalon = i_work*proj%loninc
1428   
1429       lat = proj%lat1 + deltalat
1430       lon = proj%lon1 + deltalon
1431   
1432       RETURN
1434    END SUBROUTINE ijll_latlon
1437    SUBROUTINE set_cyl(proj)
1439       implicit none
1441       ! Arguments
1442       type(proj_info), intent(inout) :: proj
1444       proj%hemi = 1.0
1446    END SUBROUTINE set_cyl
1449    SUBROUTINE llij_cyl(lat, lon, proj, i, j)
1451       implicit none
1452     
1453       ! Arguments
1454       real, intent(in) :: lat, lon
1455       real, intent(out) :: i, j
1456       type(proj_info), intent(in) :: proj
1458       ! Local variables
1459       real :: deltalat
1460       real :: deltalon
1462       ! Compute deltalat and deltalon as the difference between the input
1463       ! lat/lon and the origin lat/lon
1464       deltalat = lat - proj%lat1
1465 !      deltalon = lon - proj%stdlon
1466       deltalon = lon - proj%lon1
1468       if (deltalon <   0.) deltalon = deltalon + 360.
1469       if (deltalon > 360.) deltalon = deltalon - 360.
1471       ! Compute i/j
1472       i = deltalon/proj%loninc
1473       j = deltalat/proj%latinc
1475       if (i <= 0.)              i = i + 360./proj%loninc
1476       if (i > 360./proj%loninc) i = i - 360./proj%loninc
1478       i = i + proj%knowni
1479       j = j + proj%knownj
1481    END SUBROUTINE llij_cyl
1484    SUBROUTINE ijll_cyl(i, j, proj, lat, lon)
1485    
1486       implicit none
1487     
1488       ! Arguments
1489       real, intent(in) :: i, j
1490       real, intent(out) :: lat, lon
1491       type(proj_info), intent(in) :: proj
1493       ! Local variables
1494       real :: deltalat
1495       real :: deltalon
1496       real :: i_work, j_work
1498       i_work = i - proj%knowni 
1499       j_work = j - proj%knownj
1501       if (i_work < 0.)              i_work = i_work + 360./proj%loninc
1502       if (i_work >= 360./proj%loninc) i_work = i_work - 360./proj%loninc
1504       ! Compute deltalat and deltalon
1505       deltalat = j_work*proj%latinc
1506       deltalon = i_work*proj%loninc
1508       lat = deltalat + proj%lat1
1509 !      lon = deltalon + proj%stdlon
1510       lon = deltalon + proj%lon1
1512       if (lon < -180.) lon = lon + 360.
1513       if (lon >  180.) lon = lon - 360.
1515    END SUBROUTINE ijll_cyl
1518    SUBROUTINE set_cassini(proj)
1520       implicit none
1522       ! Arguments
1523       type(proj_info), intent(inout) :: proj
1525       ! Local variables
1526       real :: comp_lat, comp_lon
1527       logical :: global_domain
1529       proj%hemi = 1.0
1531       ! Try to determine whether this domain has global coverage
1532       if (abs(proj%lat1 - proj%latinc/2. + 90.) < 0.001 .and. &
1533           abs(mod(proj%lon1 - proj%loninc/2. - proj%stdlon,360.)) < 0.001) then
1534          global_domain = .true.
1535       else
1536          global_domain = .false.
1537       end if
1539       if (abs(proj%lat0) /= 90. .and. .not.global_domain) then
1540          call rotate_coords(proj%lat1,proj%lon1,comp_lat,comp_lon,proj%lat0,proj%lon0,proj%stdlon,-1)
1541          proj%lat1 = comp_lat
1542          proj%lon1 = comp_lon
1543       end if
1545    END SUBROUTINE set_cassini
1548    SUBROUTINE llij_cassini(lat, lon, proj, i, j)
1550       implicit none
1551     
1552       ! Arguments
1553       real, intent(in) :: lat, lon
1554       real, intent(out) :: i, j
1555       type(proj_info), intent(in) :: proj
1557       ! Local variables
1558       real :: comp_lat, comp_lon
1560       ! Convert geographic to computational lat/lon
1561       if (abs(proj%lat0) /= 90.) then
1562          call rotate_coords(lat,lon,comp_lat,comp_lon,proj%lat0,proj%lon0,proj%stdlon,-1)
1563       else
1564          comp_lat = lat
1565          comp_lon = lon
1566       end if
1568       ! Convert computational lat/lon to i/j
1569       call llij_cyl(comp_lat, comp_lon, proj, i, j)
1571    END SUBROUTINE llij_cassini
1574    SUBROUTINE ijll_cassini(i, j, proj, lat, lon)
1575    
1576       implicit none
1577     
1578       ! Arguments
1579       real, intent(in) :: i, j
1580       real, intent(out) :: lat, lon
1581       type(proj_info), intent(in) :: proj
1583       ! Local variables
1584       real :: comp_lat, comp_lon
1586       ! Convert i/j to computational lat/lon
1587       call ijll_cyl(i, j, proj, comp_lat, comp_lon)
1589       ! Convert computational to geographic lat/lon
1590       if (abs(proj%lat0) /= 90.) then
1591          call rotate_coords(comp_lat,comp_lon,lat,lon,proj%lat0,proj%lon0,proj%stdlon,1)
1592       else
1593          lat = comp_lat
1594          lon = comp_lon
1595       end if
1597    END SUBROUTINE ijll_cassini
1600    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
1601    ! Purpose: Converts between computational and geographic lat/lon for Cassini
1602    !          
1603    ! Notes: This routine was provided by Bill Skamarock, 2007-03-27
1604    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
1605    SUBROUTINE rotate_coords(ilat,ilon,olat,olon,lat_np,lon_np,lon_0,direction)
1607       IMPLICIT NONE
1609       REAL, INTENT(IN   ) :: ilat, ilon
1610       REAL, INTENT(  OUT) :: olat, olon
1611       REAL, INTENT(IN   ) :: lat_np, lon_np, lon_0
1612       INTEGER, INTENT(IN  ), OPTIONAL :: direction
1613       ! >=0, default : computational -> geographical
1614       ! < 0          : geographical  -> computational
1616       REAL :: rlat, rlon
1617       REAL :: phi_np, lam_np, lam_0, dlam
1618       REAL :: sinphi, cosphi, coslam, sinlam
1620       ! Convert all angles to radians
1621       phi_np = lat_np * rad_per_deg
1622       lam_np = lon_np * rad_per_deg
1623       lam_0  = lon_0  * rad_per_deg
1624       rlat = ilat * rad_per_deg
1625       rlon = ilon * rad_per_deg
1627       IF (PRESENT(direction) .AND. (direction < 0)) THEN
1628          ! The equations are exactly the same except for one small difference
1629          ! with respect to longitude ...
1630          dlam = PI - lam_0
1631       ELSE
1632          dlam = lam_np
1633       END IF
1634       sinphi = COS(phi_np)*COS(rlat)*COS(rlon-dlam) + SIN(phi_np)*SIN(rlat)
1635       cosphi = SQRT(1.-sinphi*sinphi)
1636       coslam = SIN(phi_np)*COS(rlat)*COS(rlon-dlam) - COS(phi_np)*SIN(rlat)
1637       sinlam = COS(rlat)*SIN(rlon-dlam)
1638       IF ( cosphi /= 0. ) THEN
1639          coslam = coslam/cosphi
1640          sinlam = sinlam/cosphi
1641       END IF
1642       olat = deg_per_rad*ASIN(sinphi)
1643       olon = deg_per_rad*(ATAN2(sinlam,coslam)-dlam-lam_0+lam_np)
1644       ! Both of my F90 text books prefer the DO-EXIT form, and claim it is faster
1645       ! when optimization is turned on (as we will always do...)
1646       DO
1647          IF (olon >= -180.) EXIT
1648          olon = olon + 360.
1649       END DO
1650       DO
1651          IF (olon <=  180.) EXIT
1652          olon = olon - 360.
1653       END DO
1655    END SUBROUTINE rotate_coords
1658    SUBROUTINE llij_rotlatlon(lat, lon, proj, i_real, j_real)
1659    
1660       IMPLICIT NONE
1661     
1662       ! Arguments
1663       REAL, INTENT(IN) :: lat, lon
1664       REAL             :: i, j
1665       REAL, INTENT(OUT) :: i_real, j_real
1666       TYPE (proj_info), INTENT(IN) :: proj
1667       
1668       ! Local variables
1669       INTEGER :: ii,imt,jj,jmt,k,krows,ncol,nrow,iri
1670       REAL(KIND=HIGH) :: dphd,dlmd !Grid increments, degrees
1671       REAL(KIND=HIGH) :: glatd  !Geographic latitude, positive north
1672       REAL(KIND=HIGH) :: glond  !Geographic longitude, positive west
1673       REAL(KIND=HIGH) :: col,d1,d2,d2r,dlm,dlm1,dlm2,dph,glat,glon,    &
1674                          pi,r2d,row,tlat,tlat1,tlat2,              &
1675                          tlon,tlon1,tlon2,tph0,tlm0,x,y,z
1677       glatd = lat
1678       glond = -lon
1679   
1680       dphd = proj%phi/REAL((proj%jydim-1)/2)
1681       dlmd = proj%lambda/REAL(proj%ixdim-1)
1683       pi = ACOS(-1.0)
1684       d2r = pi/180.
1685       r2d = 1./d2r
1686   
1687       imt = 2*proj%ixdim-1
1688       jmt = proj%jydim/2+1
1690       glat = glatd*d2r
1691       glon = glond*d2r
1692       dph = dphd*d2r
1693       dlm = dlmd*d2r
1694       tph0 = proj%lat1*d2r
1695       tlm0 = -proj%lon1*d2r
1696   
1697       x = COS(tph0)*COS(glat)*COS(glon-tlm0)+SIN(tph0)*SIN(glat)
1698       y = -COS(glat)*SIN(glon-tlm0)
1699       z = COS(tph0)*SIN(glat)-SIN(tph0)*COS(glat)*COS(glon-tlm0)
1700       tlat = r2d*ATAN(z/SQRT(x*x+y*y))
1701       tlon = r2d*ATAN(y/x)
1703       row = tlat/dphd+jmt
1704       col = tlon/dlmd+proj%ixdim
1706       if ( (row - INT(row)) .gt. 0.999) then
1707          row = row + 0.0002
1708       else if ( (col - INT(col)) .gt. 0.999) then
1709          col = col + 0.0002
1710       end if
1712       nrow = INT(row)
1713       ncol = INT(col)
1715 !      nrow = NINT(row)
1716 !      ncol = NINT(col)
1718       tlat = tlat*d2r
1719       tlon = tlon*d2r
1721   
1722       IF (proj%stagger == HH) THEN
1724          IF (mod(nrow,2) .eq. 0) then
1725             i_real = col / 2.0
1726          ELSE
1727             i_real = col / 2.0 + 0.5
1728          ENDIF
1729          j_real=row
1731   
1732          IF ((abs(MOD(nrow,2)) == 1 .AND. abs(MOD(ncol,2)) == 1) .OR. &
1733              (MOD(nrow,2) == 0 .AND. MOD(ncol,2) == 0)) THEN
1735             tlat1 = (nrow-jmt)*dph
1736             tlat2 = tlat1+dph
1737             tlon1 = (ncol-proj%ixdim)*dlm
1738             tlon2 = tlon1+dlm
1740             dlm1 = tlon-tlon1
1741             dlm2 = tlon-tlon2
1742             d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1743             d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1745             IF (d1 > d2) THEN
1746                nrow = nrow+1
1747                ncol = ncol+1
1748             END IF
1749    
1750          ELSE
1751             tlat1 = (nrow+1-jmt)*dph
1752             tlat2 = tlat1-dph
1753             tlon1 = (ncol-proj%ixdim)*dlm
1754             tlon2 = tlon1+dlm
1755             dlm1 = tlon-tlon1
1756             dlm2 = tlon-tlon2
1757             d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1758             d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1760             IF (d1 < d2) THEN
1761                nrow = nrow+1
1762             ELSE
1763                ncol = ncol+1
1764             END IF
1765          END IF
1766   
1767       ELSE IF (proj%stagger == VV) THEN
1769          IF (mod(nrow,2) .eq. 0) then
1770             i_real = col / 2.0 + 0.5
1771          ELSE
1772             i_real = col / 2.0 
1773          ENDIF
1774          j_real=row
1775   
1776          IF ((MOD(nrow,2) == 0 .AND. abs(MOD(ncol,2)) == 1) .OR. &
1777              (abs(MOD(nrow,2)) == 1 .AND. MOD(ncol,2) == 0)) THEN
1778             tlat1 = (nrow-jmt)*dph
1779             tlat2 = tlat1+dph
1780             tlon1 = (ncol-proj%ixdim)*dlm
1781             tlon2 = tlon1+dlm
1782             dlm1 = tlon-tlon1
1783             dlm2 = tlon-tlon2
1784             d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1785             d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1786     
1787             IF (d1 > d2) THEN
1788                nrow = nrow+1
1789                ncol = ncol+1
1790             END IF
1791    
1792          ELSE
1793             tlat1 = (nrow+1-jmt)*dph
1794             tlat2 = tlat1-dph
1795             tlon1 = (ncol-proj%ixdim)*dlm
1796             tlon2 = tlon1+dlm
1797             dlm1 = tlon-tlon1
1798             dlm2 = tlon-tlon2
1799             d1 = ACOS(COS(tlat)*COS(tlat1)*COS(dlm1)+SIN(tlat)*SIN(tlat1))
1800             d2 = ACOS(COS(tlat)*COS(tlat2)*COS(dlm2)+SIN(tlat)*SIN(tlat2))
1801     
1802             IF (d1 < d2) THEN
1803                nrow = nrow+1
1804             ELSE
1805                ncol = ncol+1
1806             END IF
1807          END IF
1808       END IF
1809   
1811 !!! Added next line as a Kludge - not yet understood why needed
1812       if (ncol .le. 0) ncol=ncol-1
1814       jj = nrow
1815       ii = ncol/2
1817       IF (proj%stagger == HH) THEN
1818          IF (abs(MOD(jj,2)) == 1) ii = ii+1
1819       ELSE IF (proj%stagger == VV) THEN
1820          IF (MOD(jj,2) == 0) ii=ii+1
1821       END IF
1823       i = REAL(ii)
1824       j = REAL(jj)
1826    END SUBROUTINE llij_rotlatlon
1829    SUBROUTINE ijll_rotlatlon(i, j, proj, lat,lon)
1830    
1831       IMPLICIT NONE
1832     
1833       ! Arguments
1834       REAL, INTENT(IN) :: i, j
1835       REAL, INTENT(OUT) :: lat, lon
1836       TYPE (proj_info), INTENT(IN) :: proj
1837       
1838       ! Local variables
1839       INTEGER :: ih,jh
1840       INTEGER :: midcol,midrow,ncol,iadd1,iadd2,imt,jh2,knrow,krem,kv,nrow
1841       REAL :: i_work, j_work
1842       REAL :: dphd,dlmd !Grid increments, degrees
1843       REAL(KIND=HIGH) :: arg1,arg2,d2r,fctr,glatr,glatd,glond,pi, &
1844               r2d,tlatd,tlond,tlatr,tlonr,tlm0,tph0
1845       REAL :: col
1847       i_work = i
1848       j_work = j
1849   
1850       if ( (j - INT(j)) .gt. 0.999) then
1851          j_work = j + 0.0002
1852       endif
1854       jh = INT(j_work)
1855   
1856       dphd = proj%phi/REAL((proj%jydim-1)/2)
1857       dlmd = proj%lambda/REAL(proj%ixdim-1)
1858     
1859       pi = ACOS(-1.0)
1860       d2r = pi/180.
1861       r2d = 1./d2r
1862       tph0 = proj%lat1*d2r
1863       tlm0 = -proj%lon1*d2r
1865       midrow = (proj%jydim+1)/2
1866       midcol = proj%ixdim
1868       col = 2*i_work-1+abs(MOD(jh+1,2))
1869       tlatd = (j_work-midrow)*dphd
1870       tlond = (col-midcol)*dlmd
1872        IF (proj%stagger == VV) THEN
1873           if (mod(jh,2) .eq. 0) then
1874              tlond = tlond - DLMD
1875           else
1876              tlond = tlond + DLMD
1877           end if
1878        END IF
1879     
1880       tlatr = tlatd*d2r
1881       tlonr = tlond*d2r
1882       arg1 = SIN(tlatr)*COS(tph0)+COS(tlatr)*SIN(tph0)*COS(tlonr)
1883       glatr = ASIN(arg1)
1884      
1885       glatd = glatr*r2d
1886      
1887       arg2 = COS(tlatr)*COS(tlonr)/(COS(glatr)*COS(tph0))-TAN(glatr)*TAN(tph0)
1888       IF (ABS(arg2) > 1.) arg2 = ABS(arg2)/arg2
1889       fctr = 1.
1890       IF (tlond > 0.) fctr = -1.
1891      
1892       glond = tlm0*r2d+fctr*ACOS(arg2)*r2d
1894       lat = glatd
1895       lon = -glond
1897       IF (lon .GT. +180.) lon = lon - 360.
1898       IF (lon .LT. -180.) lon = lon + 360.
1899    
1900    END SUBROUTINE ijll_rotlatlon
1903    SUBROUTINE set_gauss(proj)
1904     
1905       IMPLICIT NONE
1907       ! Argument
1908       type (proj_info), intent(inout) :: proj
1910       !  Initialize the array that will hold the Gaussian latitudes.
1912       IF ( ASSOCIATED( proj%gauss_lat ) ) THEN
1913          DEALLOCATE ( proj%gauss_lat )
1914       END IF
1916       !  Get the needed space for our array.
1918       ALLOCATE ( proj%gauss_lat(proj%nlat*2) )
1920       !  Compute the Gaussian latitudes.
1922       CALL gausll( proj%nlat*2 , proj%gauss_lat )
1924       !  Now, these could be upside down from what we want, so let's check.
1925       !  We take advantage of the equatorial symmetry to remove any sort of
1926       !  array re-ordering.
1928       IF ( ABS(proj%gauss_lat(1) - proj%lat1) .GT. 0.01 ) THEN
1929          proj%gauss_lat = -1. * proj%gauss_lat
1930       END IF
1932       !  Just a sanity check.
1934       IF ( ABS(proj%gauss_lat(1) - proj%lat1) .GT. 0.01 ) THEN
1935          PRINT '(A)','Oops, something is not right with the Gaussian latitude computation.'
1936          PRINT '(A,F8.3,A)','The input data gave the starting latitude as ',proj%lat1,'.'
1937          PRINT '(A,F8.3,A)','This routine computed the starting latitude as +-',ABS(proj%gauss_lat(1)),'.'
1938          PRINT '(A,F8.3,A)','The difference is larger than 0.01 degrees, which is not expected.'
1939          CALL wrf_error_fatal ( 'Gaussian_latitude_computation' )
1940       END IF
1942    END SUBROUTINE set_gauss
1945    SUBROUTINE gausll ( nlat , lat_sp )
1947       IMPLICIT NONE
1948    
1949       INTEGER                            :: nlat , i
1950       REAL (KIND=HIGH) , PARAMETER       :: pi = 3.141592653589793
1951       REAL (KIND=HIGH) , DIMENSION(nlat) :: cosc , gwt , sinc , colat , wos2 , lat
1952       REAL             , DIMENSION(nlat) :: lat_sp
1953    
1954       CALL lggaus(nlat, cosc, gwt, sinc, colat, wos2)
1955    
1956       DO i = 1, nlat
1957          lat(i) = ACOS(sinc(i)) * 180._HIGH / pi
1958          IF (i.gt.nlat/2) lat(i) = -lat(i)
1959       END DO
1960    
1961       lat_sp = REAL(lat)
1963    END SUBROUTINE gausll
1966    SUBROUTINE lggaus( nlat, cosc, gwt, sinc, colat, wos2 )
1968       IMPLICIT NONE
1970       !  LGGAUS finds the Gaussian latitudes by finding the roots of the
1971       !  ordinary Legendre polynomial of degree NLAT using Newton's
1972       !  iteration method.
1973       
1974       !  On entry:
1975             integer NLAT ! the number of latitudes (degree of the polynomial)
1976       
1977       !  On exit: for each Gaussian latitude
1978       !     COSC   - cos(colatitude) or sin(latitude)
1979       !     GWT    - the Gaussian weights
1980       !     SINC   - sin(colatitude) or cos(latitude)
1981       !     COLAT  - the colatitudes in radians
1982       !     WOS2   - Gaussian weight over sin**2(colatitude)
1984       REAL (KIND=HIGH) , DIMENSION(nlat) :: cosc , gwt , sinc , colat  , wos2 
1985       REAL (KIND=HIGH) , PARAMETER       :: pi = 3.141592653589793
1987       !  Convergence criterion for iteration of cos latitude
1989       REAL , PARAMETER :: xlim  = 1.0E-14
1991       INTEGER :: nzero, i, j
1992       REAL (KIND=HIGH) :: fi, fi1, a, b, g, gm, gp, gt, delta, c, d
1994       !  The number of zeros between pole and equator
1996       nzero = nlat/2
1998       !  Set first guess for cos(colat)
2000       DO i=1,nzero
2001          cosc(i) = SIN( (i-0.5)*pi/nlat + pi*0.5 )
2002       END DO
2004       !  Constants for determining the derivative of the polynomial
2005       fi  = nlat
2006       fi1 = fi+1.0
2007       a   = fi*fi1 / SQRT(4.0*fi1*fi1-1.0)
2008       b   = fi1*fi / SQRT(4.0*fi*fi-1.0)
2010       !  Loop over latitudes, iterating the search for each root
2012       DO i=1,nzero
2013          j=0
2015          !  Determine the value of the ordinary Legendre polynomial for
2016          !  the current guess root
2018          DO
2019             CALL lgord( g, cosc(i), nlat )
2020    
2021             !  Determine the derivative of the polynomial at this point
2022    
2023             CALL lgord( gm, cosc(i), nlat-1 )
2024             CALL lgord( gp, cosc(i), nlat+1 )
2025             gt = (cosc(i)*cosc(i)-1.0) / (a*gp-b*gm)
2026    
2027             !  Update the estimate of the root
2028    
2029             delta   = g*gt
2030             cosc(i) = cosc(i) - delta
2031    
2032             !  If convergence criterion has not been met, keep trying
2033    
2034             j = j+1
2035             IF( ABS(delta).GT.xlim ) CYCLE
2036    
2037             !  Determine the Gaussian weights
2038    
2039             c      = 2.0 *( 1.0-cosc(i)*cosc(i) )
2040             CALL lgord( d, cosc(i), nlat-1 )
2041             d      = d*d*fi*fi
2042             gwt(i) = c *( fi-0.5 ) / d
2043             EXIT
2045          END DO
2047       END DO
2049       !  Determine the colatitudes and sin(colat) and weights over sin**2
2051       DO i=1,nzero
2052          colat(i)= ACOS(cosc(i))
2053          sinc(i) = SIN(colat(i))
2054          wos2(i) = gwt(i) /( sinc(i)*sinc(i) )
2055       END DO
2057       !  If NLAT is odd, set values at the equator
2059       IF( MOD(nlat,2) .NE. 0 ) THEN
2060          i       = nzero+1
2061          cosc(i) = 0.0
2062          c       = 2.0
2063          CALL lgord( d, cosc(i), nlat-1 )
2064          d       = d*d*fi*fi
2065          gwt(i)  = c *( fi-0.5 ) / d
2066          colat(i)= pi*0.5
2067          sinc(i) = 1.0
2068          wos2(i) = gwt(i)
2069       END IF
2071       !  Determine the southern hemisphere values by symmetry
2073       DO i=nlat-nzero+1,nlat
2074          cosc(i) =-cosc(nlat+1-i)
2075          gwt(i)  = gwt(nlat+1-i)
2076          colat(i)= pi-colat(nlat+1-i)
2077          sinc(i) = sinc(nlat+1-i)
2078          wos2(i) = wos2(nlat+1-i)
2079       END DO
2081    END SUBROUTINE lggaus
2084    SUBROUTINE lgord( f, cosc, n )
2086       IMPLICIT NONE
2088       !  LGORD calculates the value of an ordinary Legendre polynomial at a
2089       !  specific latitude.
2090       
2091       !  On entry:
2092       !     cosc - COS(colatitude)
2093       !     n      - the degree of the polynomial
2094       
2095       !  On exit:
2096       !     f      - the value of the Legendre polynomial of degree N at
2097       !              latitude ASIN(cosc)
2099       REAL (KIND=HIGH) :: s1, c4, a, b, fk, f, cosc, colat, c1, fn, ang
2100       INTEGER :: n, k
2102       !  Determine the colatitude
2104       colat = ACOS(cosc)
2106       c1 = SQRT(2.0_HIGH)
2107       DO k=1,n
2108          c1 = c1 * SQRT( 1.0 - 1.0/(4*k*k) )
2109       END DO
2111       fn = n
2112       ang= fn * colat
2113       s1 = 0.0
2114       c4 = 1.0
2115       a  =-1.0
2116       b  = 0.0
2117       DO k=0,n,2
2118          IF (k.eq.n) c4 = 0.5 * c4
2119          s1 = s1 + c4 * COS(ang)
2120          a  = a + 2.0
2121          b  = b + 1.0
2122          fk = k
2123          ang= colat * (fn-fk-2.0)
2124          c4 = ( a * (fn-b+1.0) / ( b * (fn+fn-a) ) ) * c4
2125       END DO 
2127       f = s1 * c1
2129    END SUBROUTINE lgord
2132    SUBROUTINE llij_gauss (lat, lon, proj, i, j) 
2134       IMPLICIT NONE
2136       REAL    , INTENT(IN)  :: lat, lon
2137       REAL    , INTENT(OUT) :: i, j
2138       TYPE (proj_info), INTENT(IN) :: proj
2140       INTEGER :: n , n_low
2141       LOGICAL :: found = .FALSE.
2142       REAL    :: diff_1 , diff_nlat
2144       !  The easy one first, get the x location.  The calling routine has already made
2145       !  sure that the necessary assumptions concerning the sign of the deltalon and the
2146       !  relative east/west'ness of the longitude and the starting longitude are consistent
2147       !  to allow this easy computation.
2149       i = ( lon - proj%lon1 ) / proj%loninc + 1.
2151       !  Since this is a global data set, we need to be concerned about wrapping the
2152       !  fields around the globe.
2154 !      IF      ( ( proj%loninc .GT. 0 ) .AND. &
2155 !                ( FLOOR((lon-proj%lon1)/proj%loninc) + 1 .GE. proj%ixdim ) .AND. &
2156 !                ( lon + proj%loninc .GE. proj%lon1 + 360 ) ) THEN
2157 !! BUG: We may need to set proj%wrap, but proj is intent(in)
2158 !! WHAT IS THIS USED FOR?
2159 !!        proj%wrap = .TRUE.
2160 !         i = proj%ixdim
2161 !      ELSE IF ( ( proj%loninc .LT. 0 ) .AND. &
2162 !                ( FLOOR((lon-proj%lon1)/proj%loninc) + 1 .GE. proj%ixdim ) .AND. &
2163 !                ( lon + proj%loninc .LE. proj%lon1 - 360 ) ) THEN
2164 ! ! BUG: We may need to set proj%wrap, but proj is intent(in)
2165 ! ! WHAT IS THIS USED FOR?
2166 ! !        proj%wrap = .TRUE.
2167 !         i = proj%ixdim
2168 !      END IF
2170       !  Yet another quicky test, can we find bounding values?  If not, then we may be
2171       !  dealing with putting data to a polar projection, so just give them them maximal
2172       !  value for the location.  This is an OK assumption for the interpolation across the
2173       !  top of the pole, given how close the longitude lines are.
2175       IF ( ABS(lat) .GT. ABS(proj%gauss_lat(1)) ) THEN
2177          diff_1    = lat - proj%gauss_lat(1)
2178          diff_nlat = lat - proj%gauss_lat(proj%nlat*2)
2180          IF ( ABS(diff_1) .LT. ABS(diff_nlat) ) THEN
2181             j = 1
2182          ELSE
2183             j = proj%nlat*2
2184          END IF
2186       !  If the latitude is between the two bounding values, we have to search and interpolate.
2188       ELSE
2190          DO n = 1 , proj%nlat*2 -1
2191             IF ( ( proj%gauss_lat(n) - lat ) * ( proj%gauss_lat(n+1) - lat ) .LE. 0 ) THEN
2192                found = .TRUE.
2193                n_low = n
2194                EXIT
2195             END IF
2196          END DO
2198          !  Everything still OK?
2199   
2200          IF ( .NOT. found ) THEN
2201             PRINT '(A)','Troubles in river city.  No bounding values of latitude found in the Gaussian routines.'
2202             CALL wrf_error_fatal ( 'Gee_no_bounding_lats_Gaussian' )
2203          END IF
2205          j = ( ( proj%gauss_lat(n_low) - lat                     ) * ( n_low + 1 ) + &
2206                ( lat                   - proj%gauss_lat(n_low+1) ) * ( n_low     ) ) / &
2207                ( proj%gauss_lat(n_low) - proj%gauss_lat(n_low+1) )
2209       END IF
2211    END SUBROUTINE llij_gauss 
2212   
2213 END MODULE module_llxy