| 1 | !dis |
|---|
| 2 | !dis Open Source License/Disclaimer, Forecast Systems Laboratory |
|---|
| 3 | !dis NOAA/OAR/FSL, 325 Broadway Boulder, CO 80305 |
|---|
| 4 | !dis |
|---|
| 5 | !dis This software is distributed under the Open Source Definition, |
|---|
| 6 | !dis which may be found at http://www.opensource.org/osd.html. |
|---|
| 7 | !dis |
|---|
| 8 | !dis In particular, redistribution and use in source and binary forms, |
|---|
| 9 | !dis with or without modification, are permitted provided that the |
|---|
| 10 | !dis following conditions are met: |
|---|
| 11 | !dis |
|---|
| 12 | !dis - Redistributions of source code must retain this notice, this |
|---|
| 13 | !dis list of conditions and the following disclaimer. |
|---|
| 14 | !dis |
|---|
| 15 | !dis - Redistributions in binary form must provide access to this |
|---|
| 16 | !dis notice, this list of conditions and the following disclaimer, and |
|---|
| 17 | !dis the underlying source code. |
|---|
| 18 | !dis |
|---|
| 19 | !dis - All modifications to this software must be clearly documented, |
|---|
| 20 | !dis and are solely the responsibility of the agent making the |
|---|
| 21 | !dis modifications. |
|---|
| 22 | !dis |
|---|
| 23 | !dis - If significant modifications or enhancements are made to this |
|---|
| 24 | !dis software, the FSL Software Policy Manager |
|---|
| 25 | !dis (softwaremgr@fsl.noaa.gov) should be notified. |
|---|
| 26 | !dis |
|---|
| 27 | !dis THIS SOFTWARE AND ITS DOCUMENTATION ARE IN THE PUBLIC DOMAIN |
|---|
| 28 | !dis AND ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES |
|---|
| 29 | !dis GOVERNMENT, ITS INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND |
|---|
| 30 | !dis AGENTS MAKE NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE USEFULNESS |
|---|
| 31 | !dis OF THE SOFTWARE AND DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME |
|---|
| 32 | !dis NO RESPONSIBILITY (1) FOR THE USE OF THE SOFTWARE AND |
|---|
| 33 | !dis DOCUMENTATION; OR (2) TO PROVIDE TECHNICAL SUPPORT TO USERS. |
|---|
| 34 | !dis |
|---|
| 35 | !dis |
|---|
| 36 | |
|---|
| 37 | MODULE map_utils |
|---|
| 38 | |
|---|
| 39 | ! Module that defines constants, data structures, and |
|---|
| 40 | ! subroutines used to convert grid indices to lat/lon |
|---|
| 41 | ! and vice versa. |
|---|
| 42 | ! |
|---|
| 43 | ! SUPPORTED PROJECTIONS |
|---|
| 44 | ! --------------------- |
|---|
| 45 | ! Cylindrical Lat/Lon (code = PROJ_LATLON) |
|---|
| 46 | ! Mercator (code = PROJ_MERC) |
|---|
| 47 | ! Lambert Conformal (code = PROJ_LC) |
|---|
| 48 | ! Polar Stereographic (code = PROJ_PS) |
|---|
| 49 | ! |
|---|
| 50 | ! REMARKS |
|---|
| 51 | ! ------- |
|---|
| 52 | ! The routines contained within were adapted from routines |
|---|
| 53 | ! obtained from the NCEP w3 library. The original NCEP routines were less |
|---|
| 54 | ! flexible (e.g., polar-stereo routines only supported truelat of 60N/60S) |
|---|
| 55 | ! than what we needed, so modifications based on equations in Hoke, Hayes, and |
|---|
| 56 | ! Renninger (AFGWC/TN/79-003) were added to improve the flexibility. |
|---|
| 57 | ! Additionally, coding was improved to F90 standards and the routines were |
|---|
| 58 | ! combined into this module. |
|---|
| 59 | ! |
|---|
| 60 | ! ASSUMPTIONS |
|---|
| 61 | ! ----------- |
|---|
| 62 | ! Grid Definition: |
|---|
| 63 | ! For mercator, lambert conformal, and polar-stereographic projections, |
|---|
| 64 | ! the routines within assume the following: |
|---|
| 65 | ! |
|---|
| 66 | ! 1. Grid is dimensioned (i,j) where i is the East-West direction, |
|---|
| 67 | ! positive toward the east, and j is the north-south direction, |
|---|
| 68 | ! positive toward the north. |
|---|
| 69 | ! 2. Origin is at (1,1) and is located at the southwest corner, |
|---|
| 70 | ! regardless of hemispere. |
|---|
| 71 | ! 3. Grid spacing (dx) is always positive. |
|---|
| 72 | ! 4. Values of true latitudes must be positive for NH domains |
|---|
| 73 | ! and negative for SH domains. |
|---|
| 74 | ! |
|---|
| 75 | ! For the latlon projection, the grid origin may be at any of the |
|---|
| 76 | ! corners, and the deltalat and deltalon values can be signed to |
|---|
| 77 | ! account for this using the following convention: |
|---|
| 78 | ! Origin Location Deltalat Sign Deltalon Sign |
|---|
| 79 | ! --------------- ------------- ------------- |
|---|
| 80 | ! SW Corner + + |
|---|
| 81 | ! NE Corner - - |
|---|
| 82 | ! NW Corner - + |
|---|
| 83 | ! SE Corner + - |
|---|
| 84 | ! |
|---|
| 85 | ! Data Definitions: |
|---|
| 86 | ! 1. Any arguments that are a latitude value are expressed in |
|---|
| 87 | ! degrees north with a valid range of -90 -> 90 |
|---|
| 88 | ! 2. Any arguments that are a longitude value are expressed in |
|---|
| 89 | ! degrees east with a valid range of -180 -> 180. |
|---|
| 90 | ! 3. Distances are in meters and are always positive. |
|---|
| 91 | ! 4. The standard longitude (stdlon) is defined as the longitude |
|---|
| 92 | ! line which is parallel to the y-axis (j-direction), along |
|---|
| 93 | ! which latitude increases (NOT the absolute value of latitude, but |
|---|
| 94 | ! the actual latitude, such that latitude increases continuously |
|---|
| 95 | ! from the south pole to the north pole) as j increases. |
|---|
| 96 | ! 5. One true latitude value is required for polar-stereographic and |
|---|
| 97 | ! mercator projections, and defines at which latitude the |
|---|
| 98 | ! grid spacing is true. For lambert conformal, two true latitude |
|---|
| 99 | ! values must be specified, but may be set equal to each other to |
|---|
| 100 | ! specify a tangent projection instead of a secant projection. |
|---|
| 101 | ! |
|---|
| 102 | ! USAGE |
|---|
| 103 | ! ----- |
|---|
| 104 | ! To use the routines in this module, the calling routines must have the |
|---|
| 105 | ! following statement at the beginning of its declaration block: |
|---|
| 106 | ! USE map_utils |
|---|
| 107 | ! |
|---|
| 108 | ! The use of the module not only provides access to the necessary routines, |
|---|
| 109 | ! but also defines a structure of TYPE (proj_info) that can be used |
|---|
| 110 | ! to declare a variable of the same type to hold your map projection |
|---|
| 111 | ! information. It also defines some integer parameters that contain |
|---|
| 112 | ! the projection codes so one only has to use those variable names rather |
|---|
| 113 | ! than remembering the acutal code when using them. The basic steps are |
|---|
| 114 | ! as follows: |
|---|
| 115 | ! |
|---|
| 116 | ! 1. Ensure the "USE map_utils" is in your declarations. |
|---|
| 117 | ! 2. Declare the projection information structure as type(proj_info): |
|---|
| 118 | ! TYPE(proj_info) :: proj |
|---|
| 119 | ! 3. Populate your structure by calling the map_set routine: |
|---|
| 120 | ! CALL map_set(code,lat1,lon1,dx,stdlon,truelat1,truelat2,nx,ny,proj) |
|---|
| 121 | ! where: |
|---|
| 122 | ! code (input) = one of PROJ_LATLON, PROJ_MERC, PROJ_LC, or PROJ_PS |
|---|
| 123 | ! lat1 (input) = Latitude of grid origin point (i,j)=(1,1) |
|---|
| 124 | ! (see assumptions!) |
|---|
| 125 | ! lon1 (input) = Longitude of grid origin |
|---|
| 126 | ! dx (input) = grid spacing in meters (ignored for LATLON projections) |
|---|
| 127 | ! stdlon (input) = Standard longitude for PROJ_PS and PROJ_LC, |
|---|
| 128 | ! deltalon (see assumptions) for PROJ_LATLON, |
|---|
| 129 | ! ignored for PROJ_MERC |
|---|
| 130 | ! truelat1 (input) = 1st true latitude for PROJ_PS, PROJ_LC, and |
|---|
| 131 | ! PROJ_MERC, deltalat (see assumptions) for PROJ_LATLON |
|---|
| 132 | ! truelat2 (input) = 2nd true latitude for PROJ_LC, |
|---|
| 133 | ! ignored for all others. |
|---|
| 134 | ! nx = number of points in east-west direction |
|---|
| 135 | ! ny = number of points in north-south direction |
|---|
| 136 | ! proj (output) = The structure of type (proj_info) that will be fully |
|---|
| 137 | ! populated after this call |
|---|
| 138 | ! |
|---|
| 139 | ! 4. Now that the proj structure is populated, you may call any |
|---|
| 140 | ! of the following routines: |
|---|
| 141 | ! |
|---|
| 142 | ! latlon_to_ij(proj, lat, lon, i, j) |
|---|
| 143 | ! ij_to_latlon(proj, i, j, lat, lon) |
|---|
| 144 | ! truewind_to_gridwind(lon, proj, ugrid, vgrid, utrue, vtrue) |
|---|
| 145 | ! gridwind_to_truewind(lon, proj, utrue, vtrue, ugrid, vgrid) |
|---|
| 146 | ! compare_projections(proj1, proj2, same_proj) |
|---|
| 147 | ! |
|---|
| 148 | ! It is incumbent upon the calling routine to determine whether or |
|---|
| 149 | ! not the values returned are within your domain bounds. All values |
|---|
| 150 | ! of i, j, lat, and lon are REAL values. |
|---|
| 151 | ! |
|---|
| 152 | ! |
|---|
| 153 | ! REFERENCES |
|---|
| 154 | ! ---------- |
|---|
| 155 | ! Hoke, Hayes, and Renninger, "Map Preojections and Grid Systems for |
|---|
| 156 | ! Meteorological Applications." AFGWC/TN-79/003(Rev), Air Weather |
|---|
| 157 | ! Service, 1985. |
|---|
| 158 | ! |
|---|
| 159 | ! NCAR MM5v3 Modeling System, REGRIDDER program, module_first_guess_map.F |
|---|
| 160 | ! NCEP routines w3fb06, w3fb07, w3fb08, w3fb09, w3fb11, w3fb12 |
|---|
| 161 | ! |
|---|
| 162 | ! HISTORY |
|---|
| 163 | ! ------- |
|---|
| 164 | ! 27 Mar 2001 - Original Version |
|---|
| 165 | ! Brent L. Shaw, NOAA/FSL (CSU/CIRA) |
|---|
| 166 | ! 02 Apr 2001 - Added routines to rotate winds from true to grid |
|---|
| 167 | ! and vice versa. |
|---|
| 168 | ! Brent L. Shaw, NOAA/FSL (CSU/CIRA) |
|---|
| 169 | ! 09 Apr 2001 - Added compare_projections routine to compare two |
|---|
| 170 | ! sets of projection parameters. |
|---|
| 171 | ! |
|---|
| 172 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 173 | |
|---|
| 174 | IMPLICIT NONE |
|---|
| 175 | |
|---|
| 176 | ! Define some private constants |
|---|
| 177 | REAL, PRIVATE, PARAMETER :: pi = 3.1415927 |
|---|
| 178 | REAL, PRIVATE, PARAMETER :: deg_per_rad = 180./pi |
|---|
| 179 | REAL, PRIVATE, PARAMETER :: rad_per_deg = pi / 180. |
|---|
| 180 | |
|---|
| 181 | !! Mean Earth Radius in m. The value below is consistent |
|---|
| 182 | !! with NCEPs routines and grids. |
|---|
| 183 | !REAL, PUBLIC, PARAMETER :: earth_radius_m = 6371200. |
|---|
| 184 | REAL, PUBLIC, PARAMETER :: earth_radius_m = 3397200. |
|---|
| 185 | |
|---|
| 186 | ! Define public parameters |
|---|
| 187 | |
|---|
| 188 | ! Projection codes for proj_info structure: |
|---|
| 189 | INTEGER, PUBLIC, PARAMETER :: PROJ_LATLON = 0 |
|---|
| 190 | INTEGER, PUBLIC, PARAMETER :: PROJ_MERC = 3 |
|---|
| 191 | INTEGER, PUBLIC, PARAMETER :: PROJ_LC = 1 |
|---|
| 192 | INTEGER, PUBLIC, PARAMETER :: PROJ_PS = 2 |
|---|
| 193 | |
|---|
| 194 | |
|---|
| 195 | ! Define data structures to define various projections |
|---|
| 196 | |
|---|
| 197 | TYPE proj_info |
|---|
| 198 | |
|---|
| 199 | INTEGER :: code ! Integer code for projection type |
|---|
| 200 | REAL :: lat1 ! SW latitude (1,1) in degrees (-90->90N) |
|---|
| 201 | REAL :: lon1 ! SW longitude (1,1) in degrees (-180->180E) |
|---|
| 202 | REAL :: dx ! Grid spacing in meters at truelats, used |
|---|
| 203 | ! only for ps, lc, and merc projections |
|---|
| 204 | REAL :: dlat ! Lat increment for lat/lon grids |
|---|
| 205 | REAL :: dlon ! Lon increment for lat/lon grids |
|---|
| 206 | REAL :: stdlon ! Longitude parallel to y-axis (-180->180E) |
|---|
| 207 | REAL :: truelat1 ! First true latitude (all projections) |
|---|
| 208 | REAL :: truelat2 ! Second true lat (LC only) |
|---|
| 209 | REAL :: hemi ! 1 for NH, -1 for SH |
|---|
| 210 | REAL :: cone ! Cone factor for LC projections |
|---|
| 211 | REAL :: polei ! Computed i-location of pole point |
|---|
| 212 | REAL :: polej ! Computed j-location of pole point |
|---|
| 213 | REAL :: rsw ! Computed radius to SW corner |
|---|
| 214 | REAL :: rebydx ! Earth radius divided by dx |
|---|
| 215 | LOGICAL :: init ! Flag to indicate if this struct is |
|---|
| 216 | ! ready for use |
|---|
| 217 | INTEGER :: nx |
|---|
| 218 | INTEGER :: ny |
|---|
| 219 | END TYPE proj_info |
|---|
| 220 | |
|---|
| 221 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 222 | CONTAINS |
|---|
| 223 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 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%dx = -999.9 |
|---|
| 233 | proj%stdlon = -999.9 |
|---|
| 234 | proj%truelat1 = -999.9 |
|---|
| 235 | proj%truelat2 = -999.9 |
|---|
| 236 | proj%hemi = 0.0 |
|---|
| 237 | proj%cone = -999.9 |
|---|
| 238 | proj%polei = -999.9 |
|---|
| 239 | proj%polej = -999.9 |
|---|
| 240 | proj%rsw = -999.9 |
|---|
| 241 | proj%init = .FALSE. |
|---|
| 242 | proj%nx = -99 |
|---|
| 243 | proj%ny = -99 |
|---|
| 244 | END SUBROUTINE map_init |
|---|
| 245 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 246 | SUBROUTINE map_set(proj_code,lat1,lon1,dx,stdlon,truelat1,truelat2, & |
|---|
| 247 | idim,jdim,proj) |
|---|
| 248 | ! Given a partially filled proj_info structure, this routine computes |
|---|
| 249 | ! polei, polej, rsw, and cone (if LC projection) to complete the |
|---|
| 250 | ! structure. This allows us to eliminate redundant calculations when |
|---|
| 251 | ! calling the coordinate conversion routines multiple times for the |
|---|
| 252 | ! same map. |
|---|
| 253 | ! This will generally be the first routine called when a user wants |
|---|
| 254 | ! to be able to use the coordinate conversion routines, and it |
|---|
| 255 | ! will call the appropriate subroutines based on the |
|---|
| 256 | ! proj%code which indicates which projection type this is. |
|---|
| 257 | |
|---|
| 258 | IMPLICIT NONE |
|---|
| 259 | |
|---|
| 260 | ! Declare arguments |
|---|
| 261 | INTEGER, INTENT(IN) :: proj_code |
|---|
| 262 | REAL, INTENT(IN) :: lat1 |
|---|
| 263 | REAL, INTENT(IN) :: lon1 |
|---|
| 264 | REAL, INTENT(IN) :: dx |
|---|
| 265 | REAL, INTENT(IN) :: stdlon |
|---|
| 266 | REAL, INTENT(IN) :: truelat1 |
|---|
| 267 | REAL, INTENT(IN) :: truelat2 |
|---|
| 268 | INTEGER, INTENT(IN) :: idim |
|---|
| 269 | INTEGER, INTENT(IN) :: jdim |
|---|
| 270 | TYPE(proj_info), INTENT(OUT) :: proj |
|---|
| 271 | |
|---|
| 272 | ! Local variables |
|---|
| 273 | |
|---|
| 274 | |
|---|
| 275 | ! Executable code |
|---|
| 276 | |
|---|
| 277 | ! First, check for validity of mandatory variables in proj |
|---|
| 278 | IF ( ABS(lat1) .GT. 90.001 ) THEN |
|---|
| 279 | PRINT '(A)', 'Latitude of origin corner required as follows:' |
|---|
| 280 | PRINT '(A)', ' -90N <= lat1 < = 90.N' |
|---|
| 281 | STOP 'MAP_INIT' |
|---|
| 282 | ENDIF |
|---|
| 283 | IF ( ABS(lon1) .GT. 180.) THEN |
|---|
| 284 | PRINT '(A)', 'Longitude of origin required as follows:' |
|---|
| 285 | PRINT '(A)', ' -180E <= lon1 <= 180W' |
|---|
| 286 | STOP 'MAP_INIT' |
|---|
| 287 | ENDIF |
|---|
| 288 | IF ((dx .LE. 0.).AND.(proj_code .NE. PROJ_LATLON)) THEN |
|---|
| 289 | PRINT '(A)', 'Require grid spacing (dx) in meters be positive!' |
|---|
| 290 | STOP 'MAP_INIT' |
|---|
| 291 | ENDIF |
|---|
| 292 | IF ((ABS(stdlon) .GT. 180.).AND.(proj_code .NE. PROJ_MERC)) THEN |
|---|
| 293 | PRINT '(A)', 'Need orientation longitude (stdlon) as: ' |
|---|
| 294 | PRINT '(A)', ' -180E <= lon1 <= 180W' |
|---|
| 295 | STOP 'MAP_INIT' |
|---|
| 296 | ENDIF |
|---|
| 297 | IF (ABS(truelat1).GT.90.) THEN |
|---|
| 298 | PRINT '(A)', 'Set true latitude 1 for all projections!' |
|---|
| 299 | STOP 'MAP_INIT' |
|---|
| 300 | ENDIF |
|---|
| 301 | |
|---|
| 302 | CALL map_init(proj) |
|---|
| 303 | proj%code = proj_code |
|---|
| 304 | proj%lat1 = lat1 |
|---|
| 305 | proj%lon1 = lon1 |
|---|
| 306 | proj%dx = dx |
|---|
| 307 | proj%stdlon = stdlon |
|---|
| 308 | proj%truelat1 = truelat1 |
|---|
| 309 | proj%truelat2 = truelat2 |
|---|
| 310 | proj%nx = idim |
|---|
| 311 | proj%ny = jdim |
|---|
| 312 | IF (proj%code .NE. PROJ_LATLON) THEN |
|---|
| 313 | proj%dx = dx |
|---|
| 314 | IF (truelat1 .LT. 0.) THEN |
|---|
| 315 | proj%hemi = -1.0 |
|---|
| 316 | ELSE |
|---|
| 317 | proj%hemi = 1.0 |
|---|
| 318 | ENDIF |
|---|
| 319 | proj%rebydx = earth_radius_m / dx |
|---|
| 320 | ENDIF |
|---|
| 321 | pick_proj: SELECT CASE(proj%code) |
|---|
| 322 | |
|---|
| 323 | CASE(PROJ_PS) |
|---|
| 324 | !PRINT '(A)', 'Setting up POLAR STEREOGRAPHIC map...' |
|---|
| 325 | CALL set_ps(proj) |
|---|
| 326 | |
|---|
| 327 | CASE(PROJ_LC) |
|---|
| 328 | !PRINT '(A)', 'Setting up LAMBERT CONFORMAL map...' |
|---|
| 329 | IF (ABS(proj%truelat2) .GT. 90.) THEN |
|---|
| 330 | PRINT '(A)', 'Second true latitude not set, assuming a tangent' |
|---|
| 331 | PRINT '(A,F10.3)', 'projection at truelat1: ', proj%truelat1 |
|---|
| 332 | proj%truelat2=proj%truelat1 |
|---|
| 333 | ELSE |
|---|
| 334 | ! Ensure truelat1 < truelat2 |
|---|
| 335 | proj%truelat1 = MIN(truelat1,truelat2) |
|---|
| 336 | proj%truelat2 = MAX(truelat1,truelat2) |
|---|
| 337 | ENDIF |
|---|
| 338 | CALL set_lc(proj) |
|---|
| 339 | |
|---|
| 340 | CASE (PROJ_MERC) |
|---|
| 341 | !PRINT '(A)', 'Setting up MERCATOR map...' |
|---|
| 342 | CALL set_merc(proj) |
|---|
| 343 | |
|---|
| 344 | CASE (PROJ_LATLON) |
|---|
| 345 | !PRINT '(A)', 'Setting up CYLINDRICAL EQUIDISTANT LATLON map...' |
|---|
| 346 | ! Convert lon1 to 0->360 notation |
|---|
| 347 | IF (proj%lon1 .LT. 0.) proj%lon1 = proj%lon1 + 360. |
|---|
| 348 | |
|---|
| 349 | CASE DEFAULT |
|---|
| 350 | PRINT '(A,I2)', 'Unknown projection code: ', proj%code |
|---|
| 351 | STOP 'MAP_INIT' |
|---|
| 352 | |
|---|
| 353 | END SELECT pick_proj |
|---|
| 354 | proj%init = .TRUE. |
|---|
| 355 | RETURN |
|---|
| 356 | END SUBROUTINE map_set |
|---|
| 357 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 358 | SUBROUTINE latlon_to_ij(proj, lat, lon, i, j) |
|---|
| 359 | ! Converts input lat/lon values to the cartesian (i,j) value |
|---|
| 360 | ! for the given projection. |
|---|
| 361 | |
|---|
| 362 | IMPLICIT NONE |
|---|
| 363 | TYPE(proj_info), INTENT(IN) :: proj |
|---|
| 364 | REAL, INTENT(IN) :: lat |
|---|
| 365 | REAL, INTENT(IN) :: lon |
|---|
| 366 | REAL, INTENT(OUT) :: i |
|---|
| 367 | REAL, INTENT(OUT) :: j |
|---|
| 368 | |
|---|
| 369 | IF (.NOT.proj%init) THEN |
|---|
| 370 | PRINT '(A)', 'You have not called map_set for this projection!' |
|---|
| 371 | STOP 'LATLON_TO_IJ' |
|---|
| 372 | ENDIF |
|---|
| 373 | |
|---|
| 374 | SELECT CASE(proj%code) |
|---|
| 375 | |
|---|
| 376 | CASE(PROJ_LATLON) |
|---|
| 377 | CALL llij_latlon(lat,lon,proj,i,j) |
|---|
| 378 | |
|---|
| 379 | CASE(PROJ_MERC) |
|---|
| 380 | CALL llij_merc(lat,lon,proj,i,j) |
|---|
| 381 | |
|---|
| 382 | CASE(PROJ_PS) |
|---|
| 383 | CALL llij_ps(lat,lon,proj,i,j) |
|---|
| 384 | |
|---|
| 385 | CASE(PROJ_LC) |
|---|
| 386 | CALL llij_lc(lat,lon,proj,i,j) |
|---|
| 387 | |
|---|
| 388 | CASE DEFAULT |
|---|
| 389 | PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code |
|---|
| 390 | STOP 'LATLON_TO_IJ' |
|---|
| 391 | |
|---|
| 392 | END SELECT |
|---|
| 393 | RETURN |
|---|
| 394 | END SUBROUTINE latlon_to_ij |
|---|
| 395 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 396 | SUBROUTINE ij_to_latlon(proj, i, j, lat, lon) |
|---|
| 397 | ! Computes geographical latitude and longitude for a given (i,j) point |
|---|
| 398 | ! in a grid with a projection of proj |
|---|
| 399 | |
|---|
| 400 | IMPLICIT NONE |
|---|
| 401 | TYPE(proj_info),INTENT(IN) :: proj |
|---|
| 402 | REAL, INTENT(IN) :: i |
|---|
| 403 | REAL, INTENT(IN) :: j |
|---|
| 404 | REAL, INTENT(OUT) :: lat |
|---|
| 405 | REAL, INTENT(OUT) :: lon |
|---|
| 406 | |
|---|
| 407 | IF (.NOT.proj%init) THEN |
|---|
| 408 | PRINT '(A)', 'You have not called map_set for this projection!' |
|---|
| 409 | STOP 'IJ_TO_LATLON' |
|---|
| 410 | ENDIF |
|---|
| 411 | SELECT CASE (proj%code) |
|---|
| 412 | |
|---|
| 413 | CASE (PROJ_LATLON) |
|---|
| 414 | CALL ijll_latlon(i, j, proj, lat, lon) |
|---|
| 415 | |
|---|
| 416 | CASE (PROJ_MERC) |
|---|
| 417 | CALL ijll_merc(i, j, proj, lat, lon) |
|---|
| 418 | |
|---|
| 419 | CASE (PROJ_PS) |
|---|
| 420 | CALL ijll_ps(i, j, proj, lat, lon) |
|---|
| 421 | |
|---|
| 422 | CASE (PROJ_LC) |
|---|
| 423 | CALL ijll_lc(i, j, proj, lat, lon) |
|---|
| 424 | |
|---|
| 425 | CASE DEFAULT |
|---|
| 426 | PRINT '(A,I2)', 'Unrecognized map projection code: ', proj%code |
|---|
| 427 | STOP 'IJ_TO_LATLON' |
|---|
| 428 | |
|---|
| 429 | END SELECT |
|---|
| 430 | RETURN |
|---|
| 431 | END SUBROUTINE ij_to_latlon |
|---|
| 432 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 433 | SUBROUTINE set_ps(proj) |
|---|
| 434 | ! Initializes a polar-stereographic map projection from the partially |
|---|
| 435 | ! filled proj structure. This routine computes the radius to the |
|---|
| 436 | ! southwest corner and computes the i/j location of the pole for use |
|---|
| 437 | ! in llij_ps and ijll_ps. |
|---|
| 438 | IMPLICIT NONE |
|---|
| 439 | |
|---|
| 440 | ! Declare args |
|---|
| 441 | TYPE(proj_info), INTENT(INOUT) :: proj |
|---|
| 442 | |
|---|
| 443 | ! Local vars |
|---|
| 444 | REAL :: ala1 |
|---|
| 445 | REAL :: alo1 |
|---|
| 446 | REAL :: reflon |
|---|
| 447 | REAL :: scale_top |
|---|
| 448 | |
|---|
| 449 | ! Executable code |
|---|
| 450 | reflon = proj%stdlon + 90. |
|---|
| 451 | |
|---|
| 452 | ! Cone factor |
|---|
| 453 | proj%cone = 1.0 |
|---|
| 454 | |
|---|
| 455 | ! Compute numerator term of map scale factor |
|---|
| 456 | scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg) |
|---|
| 457 | |
|---|
| 458 | ! Compute radius to lower-left (SW) corner |
|---|
| 459 | ala1 = proj%lat1 * rad_per_deg |
|---|
| 460 | proj%rsw = proj%rebydx*COS(ala1)*scale_top/(1.+proj%hemi*SIN(ala1)) |
|---|
| 461 | |
|---|
| 462 | ! Find the pole point |
|---|
| 463 | alo1 = (proj%lon1 - reflon) * rad_per_deg |
|---|
| 464 | proj%polei = 1. - proj%rsw * COS(alo1) |
|---|
| 465 | proj%polej = 1. - proj%hemi * proj%rsw * SIN(alo1) |
|---|
| 466 | PRINT '(A,2F10.1)', 'Computed (I,J) of pole point: ',proj%polei,proj%polej |
|---|
| 467 | RETURN |
|---|
| 468 | END SUBROUTINE set_ps |
|---|
| 469 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 470 | SUBROUTINE llij_ps(lat,lon,proj,i,j) |
|---|
| 471 | ! Given latitude (-90 to 90), longitude (-180 to 180), and the |
|---|
| 472 | ! standard polar-stereographic projection information via the |
|---|
| 473 | ! public proj structure, this routine returns the i/j indices which |
|---|
| 474 | ! if within the domain range from 1->nx and 1->ny, respectively. |
|---|
| 475 | |
|---|
| 476 | IMPLICIT NONE |
|---|
| 477 | |
|---|
| 478 | ! Delcare input arguments |
|---|
| 479 | REAL, INTENT(IN) :: lat |
|---|
| 480 | REAL, INTENT(IN) :: lon |
|---|
| 481 | TYPE(proj_info),INTENT(IN) :: proj |
|---|
| 482 | |
|---|
| 483 | ! Declare output arguments |
|---|
| 484 | REAL, INTENT(OUT) :: i !(x-index) |
|---|
| 485 | REAL, INTENT(OUT) :: j !(y-index) |
|---|
| 486 | |
|---|
| 487 | ! Declare local variables |
|---|
| 488 | |
|---|
| 489 | REAL :: reflon |
|---|
| 490 | REAL :: scale_top |
|---|
| 491 | REAL :: ala |
|---|
| 492 | REAL :: alo |
|---|
| 493 | REAL :: rm |
|---|
| 494 | |
|---|
| 495 | ! BEGIN CODE |
|---|
| 496 | |
|---|
| 497 | |
|---|
| 498 | reflon = proj%stdlon + 90. |
|---|
| 499 | |
|---|
| 500 | ! Compute numerator term of map scale factor |
|---|
| 501 | |
|---|
| 502 | scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg) |
|---|
| 503 | |
|---|
| 504 | ! Find radius to desired point |
|---|
| 505 | ala = lat * rad_per_deg |
|---|
| 506 | rm = proj%rebydx * COS(ala) * scale_top/(1. + proj%hemi *SIN(ala)) |
|---|
| 507 | alo = (lon - reflon) * rad_per_deg |
|---|
| 508 | i = proj%polei + rm * COS(alo) |
|---|
| 509 | j = proj%polej + proj%hemi * rm * SIN(alo) |
|---|
| 510 | |
|---|
| 511 | RETURN |
|---|
| 512 | END SUBROUTINE llij_ps |
|---|
| 513 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 514 | SUBROUTINE ijll_ps(i, j, proj, lat, lon) |
|---|
| 515 | |
|---|
| 516 | ! This is the inverse subroutine of llij_ps. It returns the |
|---|
| 517 | ! latitude and longitude of an i/j point given the projection info |
|---|
| 518 | ! structure. |
|---|
| 519 | |
|---|
| 520 | IMPLICIT NONE |
|---|
| 521 | |
|---|
| 522 | ! Declare input arguments |
|---|
| 523 | REAL, INTENT(IN) :: i ! Column |
|---|
| 524 | REAL, INTENT(IN) :: j ! Row |
|---|
| 525 | TYPE (proj_info), INTENT(IN) :: proj |
|---|
| 526 | |
|---|
| 527 | ! Declare output arguments |
|---|
| 528 | REAL, INTENT(OUT) :: lat ! -90 -> 90 North |
|---|
| 529 | REAL, INTENT(OUT) :: lon ! -180 -> 180 East |
|---|
| 530 | |
|---|
| 531 | ! Local variables |
|---|
| 532 | REAL :: reflon |
|---|
| 533 | REAL :: scale_top |
|---|
| 534 | REAL :: xx,yy |
|---|
| 535 | REAL :: gi2, r2 |
|---|
| 536 | REAL :: arccos |
|---|
| 537 | |
|---|
| 538 | ! Begin Code |
|---|
| 539 | |
|---|
| 540 | ! Compute the reference longitude by rotating 90 degrees to the east |
|---|
| 541 | ! to find the longitude line parallel to the positive x-axis. |
|---|
| 542 | reflon = proj%stdlon + 90. |
|---|
| 543 | |
|---|
| 544 | ! Compute numerator term of map scale factor |
|---|
| 545 | scale_top = 1. + proj%hemi * SIN(proj%truelat1 * rad_per_deg) |
|---|
| 546 | |
|---|
| 547 | ! Compute radius to point of interest |
|---|
| 548 | xx = i - proj%polei |
|---|
| 549 | yy = (j - proj%polej) * proj%hemi |
|---|
| 550 | r2 = xx**2 + yy**2 |
|---|
| 551 | |
|---|
| 552 | ! Now the magic code |
|---|
| 553 | IF (r2 .EQ. 0.) THEN |
|---|
| 554 | lat = proj%hemi * 90. |
|---|
| 555 | lon = reflon |
|---|
| 556 | ELSE |
|---|
| 557 | gi2 = (proj%rebydx * scale_top)**2. |
|---|
| 558 | lat = deg_per_rad * proj%hemi * ASIN((gi2-r2)/(gi2+r2)) |
|---|
| 559 | arccos = ACOS(xx/SQRT(r2)) |
|---|
| 560 | IF (yy .GT. 0) THEN |
|---|
| 561 | lon = reflon + deg_per_rad * arccos |
|---|
| 562 | ELSE |
|---|
| 563 | lon = reflon - deg_per_rad * arccos |
|---|
| 564 | ENDIF |
|---|
| 565 | ENDIF |
|---|
| 566 | |
|---|
| 567 | ! Convert to a -180 -> 180 East convention |
|---|
| 568 | IF (lon .GT. 180.) lon = lon - 360. |
|---|
| 569 | IF (lon .LT. -180.) lon = lon + 360. |
|---|
| 570 | RETURN |
|---|
| 571 | |
|---|
| 572 | END SUBROUTINE ijll_ps |
|---|
| 573 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 574 | SUBROUTINE set_lc(proj) |
|---|
| 575 | ! Initialize the remaining items in the proj structure for a |
|---|
| 576 | ! lambert conformal grid. |
|---|
| 577 | |
|---|
| 578 | IMPLICIT NONE |
|---|
| 579 | |
|---|
| 580 | TYPE(proj_info), INTENT(INOUT) :: proj |
|---|
| 581 | |
|---|
| 582 | REAL :: arg |
|---|
| 583 | REAL :: deltalon1 |
|---|
| 584 | REAL :: tl1r |
|---|
| 585 | REAL :: ctl1r |
|---|
| 586 | |
|---|
| 587 | ! Compute cone factor |
|---|
| 588 | CALL lc_cone(proj%truelat1, proj%truelat2, proj%cone) |
|---|
| 589 | ! PRINT '(A,F8.6)', 'Computed cone factor: ', proj%cone |
|---|
| 590 | ! Compute longitude differences and ensure we stay out of the |
|---|
| 591 | ! forbidden "cut zone" |
|---|
| 592 | deltalon1 = proj%lon1 - proj%stdlon |
|---|
| 593 | IF (deltalon1 .GT. +180.) deltalon1 = deltalon1 - 360. |
|---|
| 594 | IF (deltalon1 .LT. -180.) deltalon1 = deltalon1 + 360. |
|---|
| 595 | |
|---|
| 596 | ! Convert truelat1 to radian and compute COS for later use |
|---|
| 597 | tl1r = proj%truelat1 * rad_per_deg |
|---|
| 598 | ctl1r = COS(tl1r) |
|---|
| 599 | |
|---|
| 600 | ! Compute the radius to our known lower-left (SW) corner |
|---|
| 601 | proj%rsw = proj%rebydx * ctl1r/proj%cone * & |
|---|
| 602 | (TAN((90.*proj%hemi-proj%lat1)*rad_per_deg/2.) / & |
|---|
| 603 | TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone |
|---|
| 604 | |
|---|
| 605 | ! Find pole point |
|---|
| 606 | arg = proj%cone*(deltalon1*rad_per_deg) |
|---|
| 607 | proj%polei = 1. - proj%hemi * proj%rsw * SIN(arg) |
|---|
| 608 | proj%polej = 1. + proj%rsw * COS(arg) |
|---|
| 609 | !PRINT '(A,2F10.3)', 'Computed pole i/j = ', proj%polei, proj%polej |
|---|
| 610 | RETURN |
|---|
| 611 | END SUBROUTINE set_lc |
|---|
| 612 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 613 | SUBROUTINE lc_cone(truelat1, truelat2, cone) |
|---|
| 614 | |
|---|
| 615 | ! Subroutine to compute the cone factor of a Lambert Conformal projection |
|---|
| 616 | |
|---|
| 617 | IMPLICIT NONE |
|---|
| 618 | |
|---|
| 619 | ! Input Args |
|---|
| 620 | REAL, INTENT(IN) :: truelat1 ! (-90 -> 90 degrees N) |
|---|
| 621 | REAL, INTENT(IN) :: truelat2 ! " " " " " |
|---|
| 622 | |
|---|
| 623 | ! Output Args |
|---|
| 624 | REAL, INTENT(OUT) :: cone |
|---|
| 625 | |
|---|
| 626 | ! Locals |
|---|
| 627 | |
|---|
| 628 | ! BEGIN CODE |
|---|
| 629 | |
|---|
| 630 | ! First, see if this is a secant or tangent projection. For tangent |
|---|
| 631 | ! projections, truelat1 = truelat2 and the cone is tangent to the |
|---|
| 632 | ! Earth surface at this latitude. For secant projections, the cone |
|---|
| 633 | ! intersects the Earth surface at each of the distinctly different |
|---|
| 634 | ! latitudes |
|---|
| 635 | IF (ABS(truelat1-truelat2) .GT. 0.1) THEN |
|---|
| 636 | |
|---|
| 637 | ! Compute cone factor following: |
|---|
| 638 | cone=(ALOG(COS(truelat1*rad_per_deg))-ALOG(COS(truelat2*rad_per_deg))) / & |
|---|
| 639 | (ALOG(TAN((90.-ABS(truelat1))*rad_per_deg*0.5 ))- & |
|---|
| 640 | ALOG(TAN((90.-ABS(truelat2))*rad_per_deg*0.5 )) ) |
|---|
| 641 | ELSE |
|---|
| 642 | cone = SIN(ABS(truelat1)*rad_per_deg ) |
|---|
| 643 | ENDIF |
|---|
| 644 | RETURN |
|---|
| 645 | END SUBROUTINE lc_cone |
|---|
| 646 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 647 | SUBROUTINE ijll_lc( i, j, proj, lat, lon) |
|---|
| 648 | |
|---|
| 649 | ! Subroutine to convert from the (i,j) cartesian coordinate to the |
|---|
| 650 | ! geographical latitude and longitude for a Lambert Conformal projection. |
|---|
| 651 | |
|---|
| 652 | ! History: |
|---|
| 653 | ! 25 Jul 01: Corrected by B. Shaw, NOAA/FSL |
|---|
| 654 | ! |
|---|
| 655 | IMPLICIT NONE |
|---|
| 656 | |
|---|
| 657 | ! Input Args |
|---|
| 658 | REAL, INTENT(IN) :: i ! Cartesian X coordinate |
|---|
| 659 | REAL, INTENT(IN) :: j ! Cartesian Y coordinate |
|---|
| 660 | TYPE(proj_info),INTENT(IN) :: proj ! Projection info structure |
|---|
| 661 | |
|---|
| 662 | ! Output Args |
|---|
| 663 | REAL, INTENT(OUT) :: lat ! Latitude (-90->90 deg N) |
|---|
| 664 | REAL, INTENT(OUT) :: lon ! Longitude (-180->180 E) |
|---|
| 665 | |
|---|
| 666 | ! Locals |
|---|
| 667 | REAL :: inew |
|---|
| 668 | REAL :: jnew |
|---|
| 669 | REAL :: r |
|---|
| 670 | REAL :: chi,chi1,chi2 |
|---|
| 671 | REAL :: r2 |
|---|
| 672 | REAL :: xx |
|---|
| 673 | REAL :: yy |
|---|
| 674 | |
|---|
| 675 | ! BEGIN CODE |
|---|
| 676 | |
|---|
| 677 | chi1 = (90. - proj%hemi*proj%truelat1)*rad_per_deg |
|---|
| 678 | chi2 = (90. - proj%hemi*proj%truelat2)*rad_per_deg |
|---|
| 679 | |
|---|
| 680 | ! See if we are in the southern hemispere and flip the indices |
|---|
| 681 | ! if we are. |
|---|
| 682 | IF (proj%hemi .EQ. -1.) THEN |
|---|
| 683 | inew = -i + 2. |
|---|
| 684 | jnew = -j + 2. |
|---|
| 685 | ELSE |
|---|
| 686 | inew = i |
|---|
| 687 | jnew = j |
|---|
| 688 | ENDIF |
|---|
| 689 | |
|---|
| 690 | ! Compute radius**2 to i/j location |
|---|
| 691 | xx = inew - proj%polei |
|---|
| 692 | yy = proj%polej - jnew |
|---|
| 693 | r2 = (xx*xx + yy*yy) |
|---|
| 694 | r = SQRT(r2)/proj%rebydx |
|---|
| 695 | |
|---|
| 696 | ! Convert to lat/lon |
|---|
| 697 | IF (r2 .EQ. 0.) THEN |
|---|
| 698 | lat = proj%hemi * 90. |
|---|
| 699 | lon = proj%stdlon |
|---|
| 700 | ELSE |
|---|
| 701 | |
|---|
| 702 | ! Longitude |
|---|
| 703 | lon = proj%stdlon + deg_per_rad * ATAN2(proj%hemi*xx,yy)/proj%cone |
|---|
| 704 | lon = AMOD(lon+360., 360.) |
|---|
| 705 | |
|---|
| 706 | ! Latitude. Latitude determined by solving an equation adapted |
|---|
| 707 | ! from: |
|---|
| 708 | ! Maling, D.H., 1973: Coordinate Systems and Map Projections |
|---|
| 709 | ! Equations #20 in Appendix I. |
|---|
| 710 | |
|---|
| 711 | IF (chi1 .EQ. chi2) THEN |
|---|
| 712 | chi = 2.0*ATAN( ( r/TAN(chi1) )**(1./proj%cone) * TAN(chi1*0.5) ) |
|---|
| 713 | ELSE |
|---|
| 714 | chi = 2.0*ATAN( (r*proj%cone/SIN(chi1))**(1./proj%cone) * TAN(chi1*0.5)) |
|---|
| 715 | ENDIF |
|---|
| 716 | lat = (90.0-chi*deg_per_rad)*proj%hemi |
|---|
| 717 | |
|---|
| 718 | ENDIF |
|---|
| 719 | |
|---|
| 720 | IF (lon .GT. +180.) lon = lon - 360. |
|---|
| 721 | IF (lon .LT. -180.) lon = lon + 360. |
|---|
| 722 | RETURN |
|---|
| 723 | END SUBROUTINE ijll_lc |
|---|
| 724 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 725 | SUBROUTINE llij_lc( lat, lon, proj, i, j) |
|---|
| 726 | |
|---|
| 727 | ! Subroutine to compute the geographical latitude and longitude values |
|---|
| 728 | ! to the cartesian x/y on a Lambert Conformal projection. |
|---|
| 729 | |
|---|
| 730 | IMPLICIT NONE |
|---|
| 731 | |
|---|
| 732 | ! Input Args |
|---|
| 733 | REAL, INTENT(IN) :: lat ! Latitude (-90->90 deg N) |
|---|
| 734 | REAL, INTENT(IN) :: lon ! Longitude (-180->180 E) |
|---|
| 735 | TYPE(proj_info),INTENT(IN) :: proj ! Projection info structure |
|---|
| 736 | |
|---|
| 737 | ! Output Args |
|---|
| 738 | REAL, INTENT(OUT) :: i ! Cartesian X coordinate |
|---|
| 739 | REAL, INTENT(OUT) :: j ! Cartesian Y coordinate |
|---|
| 740 | |
|---|
| 741 | ! Locals |
|---|
| 742 | REAL :: arg |
|---|
| 743 | REAL :: deltalon |
|---|
| 744 | REAL :: tl1r |
|---|
| 745 | REAL :: rm |
|---|
| 746 | REAL :: ctl1r |
|---|
| 747 | |
|---|
| 748 | |
|---|
| 749 | ! BEGIN CODE |
|---|
| 750 | |
|---|
| 751 | ! Compute deltalon between known longitude and standard lon and ensure |
|---|
| 752 | ! it is not in the cut zone |
|---|
| 753 | deltalon = lon - proj%stdlon |
|---|
| 754 | IF (deltalon .GT. +180.) deltalon = deltalon - 360. |
|---|
| 755 | IF (deltalon .LT. -180.) deltalon = deltalon + 360. |
|---|
| 756 | |
|---|
| 757 | ! Convert truelat1 to radian and compute COS for later use |
|---|
| 758 | tl1r = proj%truelat1 * rad_per_deg |
|---|
| 759 | ctl1r = COS(tl1r) |
|---|
| 760 | |
|---|
| 761 | ! Radius to desired point |
|---|
| 762 | rm = proj%rebydx * ctl1r/proj%cone * & |
|---|
| 763 | (TAN((90.*proj%hemi-lat)*rad_per_deg/2.) / & |
|---|
| 764 | TAN((90.*proj%hemi-proj%truelat1)*rad_per_deg/2.))**proj%cone |
|---|
| 765 | |
|---|
| 766 | arg = proj%cone*(deltalon*rad_per_deg) |
|---|
| 767 | i = proj%polei + proj%hemi * rm * SIN(arg) |
|---|
| 768 | j = proj%polej - rm * COS(arg) |
|---|
| 769 | |
|---|
| 770 | ! Finally, if we are in the southern hemisphere, flip the i/j |
|---|
| 771 | ! values to a coordinate system where (1,1) is the SW corner |
|---|
| 772 | ! (what we assume) which is different than the original NCEP |
|---|
| 773 | ! algorithms which used the NE corner as the origin in the |
|---|
| 774 | ! southern hemisphere (left-hand vs. right-hand coordinate?) |
|---|
| 775 | IF (proj%hemi .EQ. -1.) THEN |
|---|
| 776 | i = 2. - i |
|---|
| 777 | j = 2. - j |
|---|
| 778 | ENDIF |
|---|
| 779 | RETURN |
|---|
| 780 | END SUBROUTINE llij_lc |
|---|
| 781 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 782 | SUBROUTINE set_merc(proj) |
|---|
| 783 | |
|---|
| 784 | ! Sets up the remaining basic elements for the mercator projection |
|---|
| 785 | |
|---|
| 786 | IMPLICIT NONE |
|---|
| 787 | TYPE(proj_info), INTENT(INOUT) :: proj |
|---|
| 788 | REAL :: clain |
|---|
| 789 | |
|---|
| 790 | |
|---|
| 791 | ! Preliminary variables |
|---|
| 792 | |
|---|
| 793 | clain = COS(rad_per_deg*proj%truelat1) |
|---|
| 794 | proj%dlon = proj%dx / (earth_radius_m * clain) |
|---|
| 795 | |
|---|
| 796 | ! Compute distance from equator to origin, and store in the |
|---|
| 797 | ! proj%rsw tag. |
|---|
| 798 | |
|---|
| 799 | proj%rsw = 0. |
|---|
| 800 | IF (proj%lat1 .NE. 0.) THEN |
|---|
| 801 | proj%rsw = (ALOG(TAN(0.5*((proj%lat1+90.)*rad_per_deg))))/proj%dlon |
|---|
| 802 | ENDIF |
|---|
| 803 | RETURN |
|---|
| 804 | END SUBROUTINE set_merc |
|---|
| 805 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 806 | SUBROUTINE llij_merc(lat, lon, proj, i, j) |
|---|
| 807 | |
|---|
| 808 | ! Compute i/j coordinate from lat lon for mercator projection |
|---|
| 809 | |
|---|
| 810 | IMPLICIT NONE |
|---|
| 811 | REAL, INTENT(IN) :: lat |
|---|
| 812 | REAL, INTENT(IN) :: lon |
|---|
| 813 | TYPE(proj_info),INTENT(IN) :: proj |
|---|
| 814 | REAL,INTENT(OUT) :: i |
|---|
| 815 | REAL,INTENT(OUT) :: j |
|---|
| 816 | REAL :: deltalon |
|---|
| 817 | |
|---|
| 818 | deltalon = lon - proj%lon1 |
|---|
| 819 | IF (deltalon .LT. -180.) deltalon = deltalon + 360. |
|---|
| 820 | IF (deltalon .GT. 180.) deltalon = deltalon - 360. |
|---|
| 821 | i = 1. + (deltalon/(proj%dlon*deg_per_rad)) |
|---|
| 822 | j = 1. + (ALOG(TAN(0.5*((lat + 90.) * rad_per_deg)))) / & |
|---|
| 823 | proj%dlon - proj%rsw |
|---|
| 824 | |
|---|
| 825 | RETURN |
|---|
| 826 | END SUBROUTINE llij_merc |
|---|
| 827 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 828 | SUBROUTINE ijll_merc(i, j, proj, lat, lon) |
|---|
| 829 | |
|---|
| 830 | ! Compute the lat/lon from i/j for mercator projection |
|---|
| 831 | |
|---|
| 832 | IMPLICIT NONE |
|---|
| 833 | REAL,INTENT(IN) :: i |
|---|
| 834 | REAL,INTENT(IN) :: j |
|---|
| 835 | TYPE(proj_info),INTENT(IN) :: proj |
|---|
| 836 | REAL, INTENT(OUT) :: lat |
|---|
| 837 | REAL, INTENT(OUT) :: lon |
|---|
| 838 | |
|---|
| 839 | |
|---|
| 840 | lat = 2.0*ATAN(EXP(proj%dlon*(proj%rsw + j-1.)))*deg_per_rad - 90. |
|---|
| 841 | lon = (i-1.)*proj%dlon*deg_per_rad + proj%lon1 |
|---|
| 842 | IF (lon.GT.180.) lon = lon - 360. |
|---|
| 843 | IF (lon.LT.-180.) lon = lon + 360. |
|---|
| 844 | RETURN |
|---|
| 845 | END SUBROUTINE ijll_merc |
|---|
| 846 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 847 | SUBROUTINE llij_latlon(lat, lon, proj, i, j) |
|---|
| 848 | |
|---|
| 849 | ! Compute the i/j location of a lat/lon on a LATLON grid. |
|---|
| 850 | IMPLICIT NONE |
|---|
| 851 | REAL, INTENT(IN) :: lat |
|---|
| 852 | REAL, INTENT(IN) :: lon |
|---|
| 853 | TYPE(proj_info), INTENT(IN) :: proj |
|---|
| 854 | REAL, INTENT(OUT) :: i |
|---|
| 855 | REAL, INTENT(OUT) :: j |
|---|
| 856 | |
|---|
| 857 | REAL :: deltalat |
|---|
| 858 | REAL :: deltalon |
|---|
| 859 | REAL :: lon360 |
|---|
| 860 | REAL :: latinc |
|---|
| 861 | REAL :: loninc |
|---|
| 862 | |
|---|
| 863 | ! Extract the latitude and longitude increments for this grid |
|---|
| 864 | ! (e.g., 2.5 deg for NCEP reanalysis) from the proj structure, where |
|---|
| 865 | ! loninc is saved in the stdlon tag and latinc is saved in truelat1 |
|---|
| 866 | |
|---|
| 867 | latinc = proj%truelat1 |
|---|
| 868 | loninc = proj%stdlon |
|---|
| 869 | |
|---|
| 870 | ! Compute deltalat and deltalon as the difference between the input |
|---|
| 871 | ! lat/lon and the origin lat/lon |
|---|
| 872 | |
|---|
| 873 | deltalat = lat - proj%lat1 |
|---|
| 874 | |
|---|
| 875 | ! To account for issues around the dateline, convert the incoming |
|---|
| 876 | ! longitudes to be 0->360. |
|---|
| 877 | IF (lon .LT. 0) THEN |
|---|
| 878 | lon360 = lon + 360. |
|---|
| 879 | ELSE |
|---|
| 880 | lon360 = lon |
|---|
| 881 | ENDIF |
|---|
| 882 | deltalon = lon360 - proj%lon1 |
|---|
| 883 | IF (deltalon .LT. 0) deltalon = deltalon + 360. |
|---|
| 884 | |
|---|
| 885 | ! Compute i/j |
|---|
| 886 | i = deltalon/loninc + 1. |
|---|
| 887 | j = deltalat/latinc + 1. |
|---|
| 888 | RETURN |
|---|
| 889 | END SUBROUTINE llij_latlon |
|---|
| 890 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 891 | SUBROUTINE ijll_latlon(i, j, proj, lat, lon) |
|---|
| 892 | |
|---|
| 893 | ! Compute the lat/lon location of an i/j on a LATLON grid. |
|---|
| 894 | IMPLICIT NONE |
|---|
| 895 | REAL, INTENT(IN) :: i |
|---|
| 896 | REAL, INTENT(IN) :: j |
|---|
| 897 | TYPE(proj_info), INTENT(IN) :: proj |
|---|
| 898 | REAL, INTENT(OUT) :: lat |
|---|
| 899 | REAL, INTENT(OUT) :: lon |
|---|
| 900 | |
|---|
| 901 | REAL :: deltalat |
|---|
| 902 | REAL :: deltalon |
|---|
| 903 | REAL :: lon360 |
|---|
| 904 | REAL :: latinc |
|---|
| 905 | REAL :: loninc |
|---|
| 906 | |
|---|
| 907 | ! Extract the latitude and longitude increments for this grid |
|---|
| 908 | ! (e.g., 2.5 deg for NCEP reanalysis) from the proj structure, where |
|---|
| 909 | ! loninc is saved in the stdlon tag and latinc is saved in truelat1 |
|---|
| 910 | |
|---|
| 911 | latinc = proj%truelat1 |
|---|
| 912 | loninc = proj%stdlon |
|---|
| 913 | |
|---|
| 914 | ! Compute deltalat and deltalon |
|---|
| 915 | |
|---|
| 916 | deltalat = (j-1.)*latinc |
|---|
| 917 | deltalon = (i-1.)*loninc |
|---|
| 918 | lat = proj%lat1 + deltalat |
|---|
| 919 | lon = proj%lon1 + deltalon |
|---|
| 920 | |
|---|
| 921 | IF ((ABS(lat) .GT. 90.).OR.(ABS(deltalon) .GT.360.)) THEN |
|---|
| 922 | ! Off the earth for this grid |
|---|
| 923 | lat = -999. |
|---|
| 924 | lon = -999. |
|---|
| 925 | ELSE |
|---|
| 926 | lon = lon + 360. |
|---|
| 927 | lon = AMOD(lon,360.) |
|---|
| 928 | IF (lon .GT. 180.) lon = lon -360. |
|---|
| 929 | ENDIF |
|---|
| 930 | |
|---|
| 931 | RETURN |
|---|
| 932 | END SUBROUTINE ijll_latlon |
|---|
| 933 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 934 | SUBROUTINE gridwind_to_truewind(lon,proj,ugrid,vgrid,utrue,vtrue) |
|---|
| 935 | |
|---|
| 936 | ! Subroutine to convert a wind from grid north to true north. |
|---|
| 937 | |
|---|
| 938 | IMPLICIT NONE |
|---|
| 939 | |
|---|
| 940 | ! Arguments |
|---|
| 941 | REAL, INTENT(IN) :: lon ! Longitude of point in degrees |
|---|
| 942 | TYPE(proj_info),INTENT(IN):: proj ! Projection info structure |
|---|
| 943 | REAL, INTENT(IN) :: ugrid ! U-component, grid-relative |
|---|
| 944 | REAL, INTENT(IN) :: vgrid ! V-component, grid-relative |
|---|
| 945 | REAL, INTENT(OUT) :: utrue ! U-component, earth-relative |
|---|
| 946 | REAL, INTENT(OUT) :: vtrue ! V-component, earth-relative |
|---|
| 947 | |
|---|
| 948 | ! Locals |
|---|
| 949 | REAL :: alpha |
|---|
| 950 | REAL :: diff |
|---|
| 951 | |
|---|
| 952 | IF ((proj%code .EQ. PROJ_PS).OR.(proj%code .EQ. PROJ_LC))THEN |
|---|
| 953 | diff = lon - proj%stdlon |
|---|
| 954 | IF (diff .GT. 180.) diff = diff - 360. |
|---|
| 955 | IF (diff .LT.-180.) diff = diff + 360. |
|---|
| 956 | alpha = diff * proj%cone * rad_per_deg * SIGN(1.,proj%truelat1) |
|---|
| 957 | utrue = vgrid * SIN(alpha) + ugrid * COS(alpha) |
|---|
| 958 | vtrue = vgrid * COS(alpha) - ugrid * SIN(alpha) |
|---|
| 959 | ELSEIF ((proj%code .EQ. PROJ_MERC).OR.(proj%code .EQ. PROJ_LATLON))THEN |
|---|
| 960 | utrue = ugrid |
|---|
| 961 | vtrue = vgrid |
|---|
| 962 | ELSE |
|---|
| 963 | PRINT '(A)', 'Unrecognized projection.' |
|---|
| 964 | STOP 'GRIDWIND_TO_TRUEWIND' |
|---|
| 965 | ENDIF |
|---|
| 966 | |
|---|
| 967 | RETURN |
|---|
| 968 | END SUBROUTINE gridwind_to_truewind |
|---|
| 969 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 970 | SUBROUTINE truewind_to_gridwind(lon, proj, utrue, vtrue, ugrid, vgrid) |
|---|
| 971 | |
|---|
| 972 | ! Subroutine to compute grid-relative u/v wind components from the earth- |
|---|
| 973 | ! relative values for a given projection. |
|---|
| 974 | |
|---|
| 975 | IMPLICIT NONE |
|---|
| 976 | |
|---|
| 977 | ! Arguments |
|---|
| 978 | REAL, INTENT(IN) :: lon |
|---|
| 979 | TYPE(proj_info),INTENT(IN) :: proj |
|---|
| 980 | REAL, INTENT(IN) :: utrue |
|---|
| 981 | REAL, INTENT(IN) :: vtrue |
|---|
| 982 | REAL, INTENT(OUT) :: ugrid |
|---|
| 983 | REAL, INTENT(OUT) :: vgrid |
|---|
| 984 | |
|---|
| 985 | ! Locals |
|---|
| 986 | REAL :: alpha |
|---|
| 987 | REAL :: diff |
|---|
| 988 | |
|---|
| 989 | IF ((proj%code .EQ. PROJ_PS).OR.(proj%code .EQ. PROJ_LC))THEN |
|---|
| 990 | |
|---|
| 991 | diff = proj%stdlon - lon |
|---|
| 992 | IF (diff .GT. 180.) diff = diff - 360. |
|---|
| 993 | IF (diff .LT.-180.) diff = diff + 360. |
|---|
| 994 | alpha = diff * proj%cone * rad_per_deg * SIGN(1.,proj%truelat1) |
|---|
| 995 | ugrid = vtrue * SIN(alpha) + utrue * COS(alpha) |
|---|
| 996 | vgrid = vtrue * COS(alpha) - utrue * SIN(alpha) |
|---|
| 997 | |
|---|
| 998 | ELSEIF((proj%code .EQ. PROJ_MERC).OR.(proj%code .EQ. PROJ_LATLON)) THEN |
|---|
| 999 | ugrid = utrue |
|---|
| 1000 | vgrid = vtrue |
|---|
| 1001 | ELSE |
|---|
| 1002 | PRINT '(A)', 'Unrecognized map projection.' |
|---|
| 1003 | STOP 'TRUEWIND_TO_GRIDWIND' |
|---|
| 1004 | ENDIF |
|---|
| 1005 | RETURN |
|---|
| 1006 | END SUBROUTINE truewind_to_gridwind |
|---|
| 1007 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 1008 | SUBROUTINE compare_projections(proj1, proj2, same_proj) |
|---|
| 1009 | |
|---|
| 1010 | ! Subroutine to compare two proj_info structures to determine if the |
|---|
| 1011 | ! maps are the same. |
|---|
| 1012 | |
|---|
| 1013 | IMPLICIT NONE |
|---|
| 1014 | |
|---|
| 1015 | ! Arguments |
|---|
| 1016 | TYPE(proj_info), INTENT(IN) :: proj1 |
|---|
| 1017 | TYPE(proj_info), INTENT(IN) :: proj2 |
|---|
| 1018 | LOGICAL, INTENT(OUT) :: same_proj |
|---|
| 1019 | |
|---|
| 1020 | ! Locals |
|---|
| 1021 | |
|---|
| 1022 | same_proj = .false. |
|---|
| 1023 | |
|---|
| 1024 | ! Make sure both structures are initialized |
|---|
| 1025 | |
|---|
| 1026 | IF ((.NOT. proj1%init).OR.(.NOT.proj2%init)) THEN |
|---|
| 1027 | PRINT '(A)', 'COMPARE_PROJECTIONS: Map_Set not called yet!' |
|---|
| 1028 | same_proj = .false. |
|---|
| 1029 | ELSE |
|---|
| 1030 | same_proj = .true. |
|---|
| 1031 | ENDIF |
|---|
| 1032 | |
|---|
| 1033 | ! Check projection type |
|---|
| 1034 | IF (same_proj) THEN |
|---|
| 1035 | IF (proj1%code .NE. proj2%code) THEN |
|---|
| 1036 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different projection type.' |
|---|
| 1037 | ELSE |
|---|
| 1038 | same_proj = .true. |
|---|
| 1039 | ENDIF |
|---|
| 1040 | ENDIF |
|---|
| 1041 | |
|---|
| 1042 | ! Check corner lat/lon |
|---|
| 1043 | IF (same_proj) THEN |
|---|
| 1044 | IF ( (ABS(proj1%lat1-proj2%lat1) .GT. 0.001) .OR. & |
|---|
| 1045 | (ABS(proj1%lon1-proj2%lon1) .GT. 0.001) ) THEN |
|---|
| 1046 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different lat1/lon1' |
|---|
| 1047 | same_proj = .false. |
|---|
| 1048 | ENDIF |
|---|
| 1049 | ENDIF |
|---|
| 1050 | |
|---|
| 1051 | ! Compare dx |
|---|
| 1052 | IF ((same_proj).AND.(proj1%code .NE. PROJ_LATLON)) THEN |
|---|
| 1053 | IF ( ABS(proj1%dx-proj2%dx).GT.1. ) THEN |
|---|
| 1054 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different dx' |
|---|
| 1055 | same_proj = .false. |
|---|
| 1056 | ENDIF |
|---|
| 1057 | ENDIF |
|---|
| 1058 | ! Compare dimensions |
|---|
| 1059 | IF ((same_proj).AND.( (proj1%nx .NE. proj2%nx).OR. & |
|---|
| 1060 | (proj1%ny .NE. proj2%ny) ) ) THEN |
|---|
| 1061 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different dimensions' |
|---|
| 1062 | same_proj = .false. |
|---|
| 1063 | ENDIF |
|---|
| 1064 | |
|---|
| 1065 | IF ((same_proj).AND.(proj1%code .EQ. PROJ_LATLON)) THEN |
|---|
| 1066 | IF ( (proj1%dlat .NE. proj2%dlat).OR. & |
|---|
| 1067 | (proj1%dlon .NE. proj2%dlon)) THEN |
|---|
| 1068 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different dlat/dlon' |
|---|
| 1069 | same_proj = .false. |
|---|
| 1070 | ENDIF |
|---|
| 1071 | ENDIF |
|---|
| 1072 | |
|---|
| 1073 | ! Compare stdlon for Polar and LC projections |
|---|
| 1074 | IF ( (same_proj).AND. ( (proj1%code .EQ. PROJ_PS).OR. & |
|---|
| 1075 | (proj1%code .EQ. PROJ_LC) ) ) THEN |
|---|
| 1076 | IF (proj1%stdlon .NE. proj2%stdlon) THEN |
|---|
| 1077 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different stdlon.' |
|---|
| 1078 | same_proj = .false. |
|---|
| 1079 | ENDIF |
|---|
| 1080 | ENDIF |
|---|
| 1081 | ! Compare true latitude1 if polar stereo, mercator, or lambert |
|---|
| 1082 | IF ( (same_proj).AND. ( (proj1%code .EQ. PROJ_PS) .OR. & |
|---|
| 1083 | (proj1%code .EQ. PROJ_LC) .OR. & |
|---|
| 1084 | (proj1%code .EQ. PROJ_MERC) ) ) THEN |
|---|
| 1085 | IF (proj1%truelat1 .NE. proj2%truelat1) THEN |
|---|
| 1086 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different truelat1' |
|---|
| 1087 | same_proj = .false. |
|---|
| 1088 | ENDIF |
|---|
| 1089 | ENDIF |
|---|
| 1090 | |
|---|
| 1091 | ! Compare true latitude2 if LC |
|---|
| 1092 | IF ( (same_proj).AND.(proj1%code .EQ. PROJ_LC)) THEN |
|---|
| 1093 | IF (proj1%truelat2 .NE. proj2%truelat2) THEN |
|---|
| 1094 | PRINT '(A)', 'COMPARE_PROJECTIONS: Different truelat2' |
|---|
| 1095 | same_proj = .false. |
|---|
| 1096 | ENDIF |
|---|
| 1097 | ENDIF |
|---|
| 1098 | |
|---|
| 1099 | RETURN |
|---|
| 1100 | END SUBROUTINE compare_projections |
|---|
| 1101 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 1102 | SUBROUTINE compute_msf_lc(lat,truelat1,truelat2,msf) |
|---|
| 1103 | |
|---|
| 1104 | ! Computes the map scale factor for a Lambert Conformal grid at a given |
|---|
| 1105 | ! latitude. |
|---|
| 1106 | |
|---|
| 1107 | IMPLICIT NONE |
|---|
| 1108 | REAL, INTENT(IN) :: lat ! latitude where msf is requested |
|---|
| 1109 | REAL, INTENT(IN) :: truelat1 |
|---|
| 1110 | REAL, INTENT(IN) :: truelat2 |
|---|
| 1111 | REAL, INTENT(OUT) :: msf |
|---|
| 1112 | |
|---|
| 1113 | REAL :: cone |
|---|
| 1114 | REAL :: psi1, psix, pole |
|---|
| 1115 | |
|---|
| 1116 | CALL lc_cone(truelat1,truelat2, cone) |
|---|
| 1117 | IF (truelat1 .GE. 0.) THEN |
|---|
| 1118 | psi1 = (90. - truelat1) * rad_per_deg |
|---|
| 1119 | pole =90. |
|---|
| 1120 | ELSE |
|---|
| 1121 | psi1 = (90. + truelat1) * rad_per_deg |
|---|
| 1122 | pole = -90. |
|---|
| 1123 | ENDIF |
|---|
| 1124 | psix = (pole - lat)*rad_per_deg |
|---|
| 1125 | msf = (SIN(psi1)/SIN(psix)) & |
|---|
| 1126 | * ((TAN(psix*0.5)/TAN(psi1*0.5))**cone) |
|---|
| 1127 | RETURN |
|---|
| 1128 | END SUBROUTINE compute_msf_lc |
|---|
| 1129 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 1130 | SUBROUTINE compute_msf_ps(lat,truelat1,msf) |
|---|
| 1131 | |
|---|
| 1132 | ! Computes the map scale factor for a Polar Stereographic grid at a given |
|---|
| 1133 | ! latitude. |
|---|
| 1134 | |
|---|
| 1135 | IMPLICIT NONE |
|---|
| 1136 | REAL, INTENT(IN) :: lat ! latitude where msf is requested |
|---|
| 1137 | REAL, INTENT(IN) :: truelat1 |
|---|
| 1138 | REAL, INTENT(OUT) :: msf |
|---|
| 1139 | |
|---|
| 1140 | REAL :: psi1, psix, pole |
|---|
| 1141 | |
|---|
| 1142 | IF (truelat1 .GE. 0.) THEN |
|---|
| 1143 | psi1 = (90. - truelat1) * rad_per_deg |
|---|
| 1144 | pole =90. |
|---|
| 1145 | ELSE |
|---|
| 1146 | psi1 = (90. + truelat1) * rad_per_deg |
|---|
| 1147 | pole = -90. |
|---|
| 1148 | ENDIF |
|---|
| 1149 | psix = (pole - lat)*rad_per_deg |
|---|
| 1150 | msf = ((1.+COS(psi1))/(1.0 + COS(psix))) |
|---|
| 1151 | RETURN |
|---|
| 1152 | END SUBROUTINE compute_msf_ps |
|---|
| 1153 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 1154 | END MODULE map_utils |
|---|