1 | MODULE module_llxy |
---|
2 | |
---|
3 | ! Module that defines constants, data structures, and |
---|
4 | ! subroutines used to convert grid indices to lat/lon |
---|
5 | ! and vice versa. |
---|
6 | ! |
---|
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) |
---|
15 | ! |
---|
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. |
---|
25 | ! |
---|
26 | ! ASSUMPTIONS |
---|
27 | ! ----------- |
---|
28 | ! Grid Definition: |
---|
29 | ! For mercator, lambert conformal, and polar-stereographic projections, |
---|
30 | ! the routines within assume the following: |
---|
31 | ! |
---|
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. |
---|
40 | ! |
---|
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 + - |
---|
50 | ! |
---|
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. |
---|
67 | ! |
---|
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 |
---|
73 | ! |
---|
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: |
---|
81 | ! |
---|
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 |
---|
105 | ! |
---|
106 | ! 4. Now that the proj structure is populated, you may call either |
---|
107 | ! of the following routines: |
---|
108 | ! |
---|
109 | ! latlon_to_ij(proj, lat, lon, i, j) |
---|
110 | ! ij_to_latlon(proj, i, j, lat, lon) |
---|
111 | ! |
---|
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. |
---|
115 | ! |
---|
116 | ! |
---|
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. |
---|
122 | ! |
---|
123 | ! NCAR MM5v3 Modeling System, REGRIDDER program, module_first_guess_map.F |
---|
124 | ! NCEP routines w3fb06, w3fb07, w3fb08, w3fb09, w3fb11, w3fb12 |
---|
125 | ! |
---|
126 | ! HISTORY |
---|
127 | ! ------- |
---|
128 | ! 27 Mar 2001 - Original Version |
---|
129 | ! Brent L. Shaw, NOAA/FSL (CSU/CIRA) |
---|
130 | ! |
---|
131 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
---|
132 | |
---|
133 | USE module_wrf_error |
---|
134 | |
---|
135 | INTEGER, PARAMETER :: HH=4, VV=5 |
---|
136 | |
---|
137 | REAL, PARAMETER :: PI = 3.141592653589793 |
---|
138 | REAL, PARAMETER :: OMEGA_E = 7.292e-5 |
---|
139 | |
---|
140 | REAL, PARAMETER :: DEG_PER_RAD = 180./PI |
---|
141 | REAL, PARAMETER :: RAD_PER_DEG = PI/180. |
---|
142 | |
---|
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 |
---|
147 | |
---|
148 | REAL, PARAMETER :: A_NAD83 = 6378137. |
---|
149 | REAL, PARAMETER :: RE_NAD83 = A_NAD83 |
---|
150 | REAL, PARAMETER :: E_NAD83 = 0.0818187034 |
---|
151 | |
---|
152 | REAL, PARAMETER :: EARTH_RADIUS_M = 6370000. |
---|
153 | REAL, PARAMETER :: EARTH_CIRC_M = 2.*PI*EARTH_RADIUS_M |
---|
154 | |
---|
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 |
---|
165 | |
---|
166 | ! Define some private constants |
---|
167 | INTEGER, PRIVATE, PARAMETER :: HIGH = 8 |
---|
168 | |
---|
169 | TYPE proj_info |
---|
170 | |
---|
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 |
---|
217 | |
---|
218 | END TYPE proj_info |
---|
219 | |
---|
220 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
---|
221 | CONTAINS |
---|
222 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
---|
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%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 |
---|
264 | |
---|
265 | |
---|
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 |
---|
304 | |
---|
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 |
---|
541 | |
---|
542 | pick_proj: SELECT CASE(proj%code) |
---|
543 | |
---|
544 | CASE(PROJ_PS) |
---|
545 | CALL set_ps(proj) |
---|
546 | |
---|
547 | CASE(PROJ_PS_WGS84) |
---|
548 | CALL set_ps_wgs84(proj) |
---|
549 | |
---|
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. |
---|
577 | |
---|
578 | RETURN |
---|
579 | |
---|
580 | END SUBROUTINE map_set |
---|
581 | |
---|
582 | |
---|
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) |
---|
609 | |
---|
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) |
---|
624 | |
---|
625 | CASE(PROJ_CASSINI) |
---|
626 | CALL llij_cassini(lat,lon,proj,i,j) |
---|
627 | |
---|
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 |
---|
636 | |
---|
637 | RETURN |
---|
638 | |
---|
639 | END SUBROUTINE latlon_to_ij |
---|
640 | |
---|
641 | |
---|
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) |
---|
667 | |
---|
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 |
---|
693 | |
---|
694 | |
---|
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) |
---|
725 | |
---|
726 | RETURN |
---|
727 | |
---|
728 | END SUBROUTINE set_ps |
---|
729 | |
---|
730 | |
---|
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 |
---|
772 | |
---|
773 | END SUBROUTINE llij_ps |
---|
774 | |
---|
775 | |
---|
776 | SUBROUTINE ijll_ps(i, j, proj, lat, lon) |
---|
777 | |
---|
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. |
---|
832 | |
---|
833 | RETURN |
---|
834 | |
---|
835 | END SUBROUTINE ijll_ps |
---|
836 | |
---|
837 | |
---|
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. |
---|
843 | |
---|
844 | IMPLICIT NONE |
---|
845 | |
---|
846 | ! Arguments |
---|
847 | TYPE(proj_info), INTENT(INOUT) :: proj |
---|
848 | |
---|
849 | ! Local variables |
---|
850 | real :: h, mc, tc, t, rho |
---|
851 | |
---|
852 | h = proj%hemi |
---|
853 | |
---|
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 )) |
---|
857 | |
---|
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) |
---|
864 | |
---|
865 | RETURN |
---|
866 | |
---|
867 | END SUBROUTINE set_ps_wgs84 |
---|
868 | |
---|
869 | |
---|
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 |
---|
887 | |
---|
888 | h = proj%hemi |
---|
889 | |
---|
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 )) |
---|
893 | |
---|
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)) |
---|
896 | |
---|
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) |
---|
901 | |
---|
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 |
---|
907 | |
---|
908 | END SUBROUTINE llij_ps_wgs84 |
---|
909 | |
---|
910 | |
---|
911 | SUBROUTINE ijll_ps_wgs84(i, j, proj, lat, lon) |
---|
912 | |
---|
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 |
---|
925 | |
---|
926 | ! Local variables |
---|
927 | real :: h, mc, tc, t, rho, x, y |
---|
928 | real :: chi, a, b, c, d |
---|
929 | |
---|
930 | h = proj%hemi |
---|
931 | x = (i - proj%knowni + proj%polei) |
---|
932 | y = (j - proj%knownj + proj%polej) |
---|
933 | |
---|
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 )) |
---|
937 | |
---|
938 | rho = sqrt((x*proj%dx)**2.0 + (y*proj%dx)**2.0) |
---|
939 | t = rho * tc / (A_WGS84 * mc) |
---|
940 | |
---|
941 | lon = h*proj%stdlon + h*atan2(h*x,h*(-y)) |
---|
942 | |
---|
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. |
---|
948 | |
---|
949 | lat = chi + sin(2.*chi)*(a + cos(2.*chi)*(b + cos(2.*chi)*(c + d*cos(2.*chi)))) |
---|
950 | lat = h * lat |
---|
951 | |
---|
952 | lat = lat*deg_per_rad |
---|
953 | lon = lon*deg_per_rad |
---|
954 | |
---|
955 | RETURN |
---|
956 | |
---|
957 | END SUBROUTINE ijll_ps_wgs84 |
---|
958 | |
---|
959 | |
---|
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. |
---|
965 | |
---|
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 |
---|
973 | |
---|
974 | h = proj%hemi |
---|
975 | |
---|
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) |
---|
978 | |
---|
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))) |
---|
982 | |
---|
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))) |
---|
986 | |
---|
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 |
---|
992 | |
---|
993 | proj%bigc = m1**2.0 + proj%nc*q1 |
---|
994 | |
---|
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))) |
---|
999 | |
---|
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 |
---|
1002 | |
---|
1003 | proj%polei = proj%rho0 * sin(h*theta) |
---|
1004 | proj%polej = proj%rho0 - proj%rho0 * cos(h*theta) |
---|
1005 | |
---|
1006 | RETURN |
---|
1007 | |
---|
1008 | END SUBROUTINE set_albers_nad83 |
---|
1009 | |
---|
1010 | |
---|
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 |
---|
1028 | |
---|
1029 | h = proj%hemi |
---|
1030 | |
---|
1031 | sinphi = sin(h*lat*rad_per_deg) |
---|
1032 | |
---|
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))) |
---|
1036 | |
---|
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 |
---|
1039 | |
---|
1040 | i = h*rho*sin(theta) |
---|
1041 | j = h*proj%rho0 - h*rho*cos(theta) |
---|
1042 | |
---|
1043 | ! Get i/j relative to reference i/j |
---|
1044 | i = proj%knowni + (i - proj%polei) |
---|
1045 | j = proj%knownj + (j - proj%polej) |
---|
1046 | |
---|
1047 | RETURN |
---|
1048 | |
---|
1049 | END SUBROUTINE llij_albers_nad83 |
---|
1050 | |
---|
1051 | |
---|
1052 | SUBROUTINE ijll_albers_nad83(i, j, proj, lat, lon) |
---|
1053 | |
---|
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 |
---|
1066 | |
---|
1067 | ! Local variables |
---|
1068 | real :: h, q, rho, theta, beta, x, y |
---|
1069 | real :: a, b, c |
---|
1070 | |
---|
1071 | h = proj%hemi |
---|
1072 | |
---|
1073 | x = (i - proj%knowni + proj%polei) |
---|
1074 | y = (j - proj%knownj + proj%polej) |
---|
1075 | |
---|
1076 | rho = sqrt(x**2.0 + (proj%rho0 - y)**2.0) |
---|
1077 | theta = atan2(x, proj%rho0-y) |
---|
1078 | |
---|
1079 | q = (proj%bigc - (rho*proj%nc*proj%dx/A_NAD83)**2.0) / proj%nc |
---|
1080 | |
---|
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. |
---|
1085 | |
---|
1086 | lat = beta + a*sin(2.*beta) + b*sin(4.*beta) + c*sin(6.*beta) |
---|
1087 | |
---|
1088 | lat = h*lat*deg_per_rad |
---|
1089 | lon = proj%stdlon + theta*deg_per_rad/proj%nc |
---|
1090 | |
---|
1091 | RETURN |
---|
1092 | |
---|
1093 | END SUBROUTINE ijll_albers_nad83 |
---|
1094 | |
---|
1095 | |
---|
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 |
---|
1133 | |
---|
1134 | END SUBROUTINE set_lc |
---|
1135 | |
---|
1136 | |
---|
1137 | SUBROUTINE lc_cone(truelat1, truelat2, cone) |
---|
1138 | |
---|
1139 | ! Subroutine to compute the cone factor of a Lambert Conformal projection |
---|
1140 | |
---|
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 |
---|
1167 | |
---|
1168 | RETURN |
---|
1169 | |
---|
1170 | END SUBROUTINE lc_cone |
---|
1171 | |
---|
1172 | |
---|
1173 | SUBROUTINE ijll_lc( i, j, proj, lat, lon) |
---|
1174 | |
---|
1175 | ! Subroutine to convert from the (i,j) cartesian coordinate to the |
---|
1176 | ! geographical latitude and longitude for a Lambert Conformal projection. |
---|
1177 | |
---|
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 = AMOD(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. |
---|
1243 | |
---|
1244 | RETURN |
---|
1245 | |
---|
1246 | END SUBROUTINE ijll_lc |
---|
1247 | |
---|
1248 | |
---|
1249 | SUBROUTINE llij_lc( lat, lon, proj, i, j) |
---|
1250 | |
---|
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 |
---|
1301 | |
---|
1302 | RETURN |
---|
1303 | END SUBROUTINE llij_lc |
---|
1304 | |
---|
1305 | |
---|
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 |
---|
1327 | |
---|
1328 | RETURN |
---|
1329 | |
---|
1330 | END SUBROUTINE set_merc |
---|
1331 | |
---|
1332 | |
---|
1333 | SUBROUTINE llij_merc(lat, lon, proj, i, j) |
---|
1334 | |
---|
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 |
---|
1353 | |
---|
1354 | END SUBROUTINE llij_merc |
---|
1355 | |
---|
1356 | |
---|
1357 | SUBROUTINE ijll_merc(i, j, proj, lat, lon) |
---|
1358 | |
---|
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 |
---|
1374 | |
---|
1375 | END SUBROUTINE ijll_merc |
---|
1376 | |
---|
1377 | |
---|
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 |
---|
1399 | |
---|
1400 | i = i + proj%knowni |
---|
1401 | j = j + proj%knownj |
---|
1402 | |
---|
1403 | RETURN |
---|
1404 | |
---|
1405 | END SUBROUTINE llij_latlon |
---|
1406 | |
---|
1407 | |
---|
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 |
---|
1424 | |
---|
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 |
---|
1433 | |
---|
1434 | END SUBROUTINE ijll_latlon |
---|
1435 | |
---|
1436 | |
---|
1437 | SUBROUTINE set_cyl(proj) |
---|
1438 | |
---|
1439 | implicit none |
---|
1440 | |
---|
1441 | ! Arguments |
---|
1442 | type(proj_info), intent(inout) :: proj |
---|
1443 | |
---|
1444 | proj%hemi = 1.0 |
---|
1445 | |
---|
1446 | END SUBROUTINE set_cyl |
---|
1447 | |
---|
1448 | |
---|
1449 | SUBROUTINE llij_cyl(lat, lon, proj, i, j) |
---|
1450 | |
---|
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 |
---|
1457 | |
---|
1458 | ! Local variables |
---|
1459 | real :: deltalat |
---|
1460 | real :: deltalon |
---|
1461 | |
---|
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 |
---|
1467 | |
---|
1468 | if (deltalon < 0.) deltalon = deltalon + 360. |
---|
1469 | if (deltalon > 360.) deltalon = deltalon - 360. |
---|
1470 | |
---|
1471 | ! Compute i/j |
---|
1472 | i = deltalon/proj%loninc |
---|
1473 | j = deltalat/proj%latinc |
---|
1474 | |
---|
1475 | if (i <= 0.) i = i + 360./proj%loninc |
---|
1476 | if (i > 360./proj%loninc) i = i - 360./proj%loninc |
---|
1477 | |
---|
1478 | i = i + proj%knowni |
---|
1479 | j = j + proj%knownj |
---|
1480 | |
---|
1481 | END SUBROUTINE llij_cyl |
---|
1482 | |
---|
1483 | |
---|
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 |
---|
1492 | |
---|
1493 | ! Local variables |
---|
1494 | real :: deltalat |
---|
1495 | real :: deltalon |
---|
1496 | real :: i_work, j_work |
---|
1497 | |
---|
1498 | i_work = i - proj%knowni |
---|
1499 | j_work = j - proj%knownj |
---|
1500 | |
---|
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 |
---|
1503 | |
---|
1504 | ! Compute deltalat and deltalon |
---|
1505 | deltalat = j_work*proj%latinc |
---|
1506 | deltalon = i_work*proj%loninc |
---|
1507 | |
---|
1508 | lat = deltalat + proj%lat1 |
---|
1509 | ! lon = deltalon + proj%stdlon |
---|
1510 | lon = deltalon + proj%lon1 |
---|
1511 | |
---|
1512 | if (lon < -180.) lon = lon + 360. |
---|
1513 | if (lon > 180.) lon = lon - 360. |
---|
1514 | |
---|
1515 | END SUBROUTINE ijll_cyl |
---|
1516 | |
---|
1517 | |
---|
1518 | SUBROUTINE set_cassini(proj) |
---|
1519 | |
---|
1520 | implicit none |
---|
1521 | |
---|
1522 | ! Arguments |
---|
1523 | type(proj_info), intent(inout) :: proj |
---|
1524 | |
---|
1525 | ! Local variables |
---|
1526 | real :: comp_lat, comp_lon |
---|
1527 | logical :: global_domain |
---|
1528 | |
---|
1529 | proj%hemi = 1.0 |
---|
1530 | |
---|
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 |
---|
1538 | |
---|
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 |
---|
1544 | |
---|
1545 | END SUBROUTINE set_cassini |
---|
1546 | |
---|
1547 | |
---|
1548 | SUBROUTINE llij_cassini(lat, lon, proj, i, j) |
---|
1549 | |
---|
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 |
---|
1556 | |
---|
1557 | ! Local variables |
---|
1558 | real :: comp_lat, comp_lon |
---|
1559 | |
---|
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 |
---|
1567 | |
---|
1568 | ! Convert computational lat/lon to i/j |
---|
1569 | call llij_cyl(comp_lat, comp_lon, proj, i, j) |
---|
1570 | |
---|
1571 | END SUBROUTINE llij_cassini |
---|
1572 | |
---|
1573 | |
---|
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 |
---|
1582 | |
---|
1583 | ! Local variables |
---|
1584 | real :: comp_lat, comp_lon |
---|
1585 | |
---|
1586 | ! Convert i/j to computational lat/lon |
---|
1587 | call ijll_cyl(i, j, proj, comp_lat, comp_lon) |
---|
1588 | |
---|
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 |
---|
1596 | |
---|
1597 | END SUBROUTINE ijll_cassini |
---|
1598 | |
---|
1599 | |
---|
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) |
---|
1606 | |
---|
1607 | IMPLICIT NONE |
---|
1608 | |
---|
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 |
---|
1615 | |
---|
1616 | REAL :: rlat, rlon |
---|
1617 | REAL :: phi_np, lam_np, lam_0, dlam |
---|
1618 | REAL :: sinphi, cosphi, coslam, sinlam |
---|
1619 | |
---|
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 |
---|
1626 | |
---|
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 |
---|
1654 | |
---|
1655 | END SUBROUTINE rotate_coords |
---|
1656 | |
---|
1657 | |
---|
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 |
---|
1676 | |
---|
1677 | glatd = lat |
---|
1678 | glond = -lon |
---|
1679 | |
---|
1680 | dphd = proj%phi/REAL((proj%jydim-1)/2) |
---|
1681 | dlmd = proj%lambda/REAL(proj%ixdim-1) |
---|
1682 | |
---|
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 |
---|
1689 | |
---|
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) |
---|
1702 | |
---|
1703 | row = tlat/dphd+jmt |
---|
1704 | col = tlon/dlmd+proj%ixdim |
---|
1705 | |
---|
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 |
---|
1711 | |
---|
1712 | nrow = INT(row) |
---|
1713 | ncol = INT(col) |
---|
1714 | |
---|
1715 | ! nrow = NINT(row) |
---|
1716 | ! ncol = NINT(col) |
---|
1717 | |
---|
1718 | tlat = tlat*d2r |
---|
1719 | tlon = tlon*d2r |
---|
1720 | |
---|
1721 | |
---|
1722 | IF (proj%stagger == HH) THEN |
---|
1723 | |
---|
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 |
---|
1730 | |
---|
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 |
---|
1734 | |
---|
1735 | tlat1 = (nrow-jmt)*dph |
---|
1736 | tlat2 = tlat1+dph |
---|
1737 | tlon1 = (ncol-proj%ixdim)*dlm |
---|
1738 | tlon2 = tlon1+dlm |
---|
1739 | |
---|
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)) |
---|
1744 | |
---|
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)) |
---|
1759 | |
---|
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 |
---|
1768 | |
---|
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 | |
---|
1810 | |
---|
1811 | !!! Added next line as a Kludge - not yet understood why needed |
---|
1812 | if (ncol .le. 0) ncol=ncol-1 |
---|
1813 | |
---|
1814 | jj = nrow |
---|
1815 | ii = ncol/2 |
---|
1816 | |
---|
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 |
---|
1822 | |
---|
1823 | i = REAL(ii) |
---|
1824 | j = REAL(jj) |
---|
1825 | |
---|
1826 | END SUBROUTINE llij_rotlatlon |
---|
1827 | |
---|
1828 | |
---|
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 |
---|
1846 | |
---|
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 |
---|
1853 | |
---|
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 |
---|
1864 | |
---|
1865 | midrow = (proj%jydim+1)/2 |
---|
1866 | midcol = proj%ixdim |
---|
1867 | |
---|
1868 | col = 2*i_work-1+abs(MOD(jh+1,2)) |
---|
1869 | tlatd = (j_work-midrow)*dphd |
---|
1870 | tlond = (col-midcol)*dlmd |
---|
1871 | |
---|
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 |
---|
1893 | |
---|
1894 | lat = glatd |
---|
1895 | lon = -glond |
---|
1896 | |
---|
1897 | IF (lon .GT. +180.) lon = lon - 360. |
---|
1898 | IF (lon .LT. -180.) lon = lon + 360. |
---|
1899 | |
---|
1900 | END SUBROUTINE ijll_rotlatlon |
---|
1901 | |
---|
1902 | |
---|
1903 | SUBROUTINE set_gauss(proj) |
---|
1904 | |
---|
1905 | IMPLICIT NONE |
---|
1906 | |
---|
1907 | ! Argument |
---|
1908 | type (proj_info), intent(inout) :: proj |
---|
1909 | |
---|
1910 | ! Initialize the array that will hold the Gaussian latitudes. |
---|
1911 | |
---|
1912 | IF ( ASSOCIATED( proj%gauss_lat ) ) THEN |
---|
1913 | DEALLOCATE ( proj%gauss_lat ) |
---|
1914 | END IF |
---|
1915 | |
---|
1916 | ! Get the needed space for our array. |
---|
1917 | |
---|
1918 | ALLOCATE ( proj%gauss_lat(proj%nlat*2) ) |
---|
1919 | |
---|
1920 | ! Compute the Gaussian latitudes. |
---|
1921 | |
---|
1922 | CALL gausll( proj%nlat*2 , proj%gauss_lat ) |
---|
1923 | |
---|
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. |
---|
1927 | |
---|
1928 | IF ( ABS(proj%gauss_lat(1) - proj%lat1) .GT. 0.01 ) THEN |
---|
1929 | proj%gauss_lat = -1. * proj%gauss_lat |
---|
1930 | END IF |
---|
1931 | |
---|
1932 | ! Just a sanity check. |
---|
1933 | |
---|
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 |
---|
1941 | |
---|
1942 | END SUBROUTINE set_gauss |
---|
1943 | |
---|
1944 | |
---|
1945 | SUBROUTINE gausll ( nlat , lat_sp ) |
---|
1946 | |
---|
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) |
---|
1962 | |
---|
1963 | END SUBROUTINE gausll |
---|
1964 | |
---|
1965 | |
---|
1966 | SUBROUTINE lggaus( nlat, cosc, gwt, sinc, colat, wos2 ) |
---|
1967 | |
---|
1968 | IMPLICIT NONE |
---|
1969 | |
---|
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) |
---|
1983 | |
---|
1984 | REAL (KIND=HIGH) , DIMENSION(nlat) :: cosc , gwt , sinc , colat , wos2 |
---|
1985 | REAL (KIND=HIGH) , PARAMETER :: pi = 3.141592653589793 |
---|
1986 | |
---|
1987 | ! Convergence criterion for iteration of cos latitude |
---|
1988 | |
---|
1989 | REAL , PARAMETER :: xlim = 1.0E-14 |
---|
1990 | |
---|
1991 | INTEGER :: nzero, i, j |
---|
1992 | REAL (KIND=HIGH) :: fi, fi1, a, b, g, gm, gp, gt, delta, c, d |
---|
1993 | |
---|
1994 | ! The number of zeros between pole and equator |
---|
1995 | |
---|
1996 | nzero = nlat/2 |
---|
1997 | |
---|
1998 | ! Set first guess for cos(colat) |
---|
1999 | |
---|
2000 | DO i=1,nzero |
---|
2001 | cosc(i) = SIN( (i-0.5)*pi/nlat + pi*0.5 ) |
---|
2002 | END DO |
---|
2003 | |
---|
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) |
---|
2009 | |
---|
2010 | ! Loop over latitudes, iterating the search for each root |
---|
2011 | |
---|
2012 | DO i=1,nzero |
---|
2013 | j=0 |
---|
2014 | |
---|
2015 | ! Determine the value of the ordinary Legendre polynomial for |
---|
2016 | ! the current guess root |
---|
2017 | |
---|
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 |
---|
2044 | |
---|
2045 | END DO |
---|
2046 | |
---|
2047 | END DO |
---|
2048 | |
---|
2049 | ! Determine the colatitudes and sin(colat) and weights over sin**2 |
---|
2050 | |
---|
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 |
---|
2056 | |
---|
2057 | ! If NLAT is odd, set values at the equator |
---|
2058 | |
---|
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 |
---|
2070 | |
---|
2071 | ! Determine the southern hemisphere values by symmetry |
---|
2072 | |
---|
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 |
---|
2080 | |
---|
2081 | END SUBROUTINE lggaus |
---|
2082 | |
---|
2083 | |
---|
2084 | SUBROUTINE lgord( f, cosc, n ) |
---|
2085 | |
---|
2086 | IMPLICIT NONE |
---|
2087 | |
---|
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) |
---|
2098 | |
---|
2099 | REAL (KIND=HIGH) :: s1, c4, a, b, fk, f, cosc, colat, c1, fn, ang |
---|
2100 | INTEGER :: n, k |
---|
2101 | |
---|
2102 | ! Determine the colatitude |
---|
2103 | |
---|
2104 | colat = ACOS(cosc) |
---|
2105 | |
---|
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 |
---|
2110 | |
---|
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 |
---|
2126 | |
---|
2127 | f = s1 * c1 |
---|
2128 | |
---|
2129 | END SUBROUTINE lgord |
---|
2130 | |
---|
2131 | |
---|
2132 | SUBROUTINE llij_gauss (lat, lon, proj, i, j) |
---|
2133 | |
---|
2134 | IMPLICIT NONE |
---|
2135 | |
---|
2136 | REAL , INTENT(IN) :: lat, lon |
---|
2137 | REAL , INTENT(OUT) :: i, j |
---|
2138 | TYPE (proj_info), INTENT(IN) :: proj |
---|
2139 | |
---|
2140 | INTEGER :: n , n_low |
---|
2141 | LOGICAL :: found = .FALSE. |
---|
2142 | REAL :: diff_1 , diff_nlat |
---|
2143 | |
---|
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. |
---|
2148 | |
---|
2149 | i = ( lon - proj%lon1 ) / proj%loninc + 1. |
---|
2150 | |
---|
2151 | ! Since this is a global data set, we need to be concerned about wrapping the |
---|
2152 | ! fields around the globe. |
---|
2153 | |
---|
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 |
---|
2169 | |
---|
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. |
---|
2174 | |
---|
2175 | IF ( ABS(lat) .GT. ABS(proj%gauss_lat(1)) ) THEN |
---|
2176 | |
---|
2177 | diff_1 = lat - proj%gauss_lat(1) |
---|
2178 | diff_nlat = lat - proj%gauss_lat(proj%nlat*2) |
---|
2179 | |
---|
2180 | IF ( ABS(diff_1) .LT. ABS(diff_nlat) ) THEN |
---|
2181 | j = 1 |
---|
2182 | ELSE |
---|
2183 | j = proj%nlat*2 |
---|
2184 | END IF |
---|
2185 | |
---|
2186 | ! If the latitude is between the two bounding values, we have to search and interpolate. |
---|
2187 | |
---|
2188 | ELSE |
---|
2189 | |
---|
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 |
---|
2197 | |
---|
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 |
---|
2204 | |
---|
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) ) |
---|
2208 | |
---|
2209 | END IF |
---|
2210 | |
---|
2211 | END SUBROUTINE llij_gauss |
---|
2212 | |
---|
2213 | END MODULE module_llxy |
---|