NCEPLIBS-ip 4.0.0
ip_rot_equid_cylind_grid_mod.f90
1module ip_rot_equid_cylind_grid_mod
2 use iso_fortran_env, only: real64
5 use constants_mod, only: dpr, pi
6 use earth_radius_mod
7 implicit none
8
9 private
11
12 integer, parameter :: kd = real64
13
15 real(kd) :: clat0, dlats, dlons, rlon0, slat0, wbd, sbd
16 integer :: irot
17 contains
18 procedure :: init_grib1
19 procedure :: init_grib2
20 procedure :: gdswzd => gdswzd_rot_equid_cylind
22
23 INTEGER :: IROT
24
25 REAL(KIND=kd) :: rerth
26 REAL(KIND=kd) :: clat0, dlats, dlons
27 REAL(KIND=kd) :: rlon0, slat0
28
29
30CONTAINS
31
32 subroutine init_grib1(self, g1_desc)
33 class(ip_rot_equid_cylind_grid), intent(inout) :: self
34 type(grib1_descriptor), intent(in) :: g1_desc
35
36 real(kd) :: rlat1, rlon1, rlat0, rlat2, rlon2, nbd, ebd
37 real(kd) :: hs, hs2, slat1, slat2, slatr, clon1, clon2, clat1, clat2, clatr, clonr, rlonr, rlatr
38 integer :: iscale
39
40 associate(kgds => g1_desc%gds)
41 self%rerth = 6.3712e6_kd
42 self%eccen_squared = 0d0
43
44 rlat1=kgds(4)*1.e-3_kd
45 rlon1=kgds(5)*1.e-3_kd
46 rlat0=kgds(7)*1.e-3_kd
47 self%RLON0=kgds(8)*1.e-3_kd
48 rlat2=kgds(12)*1.e-3_kd
49 rlon2=kgds(13)*1.e-3_kd
50
51 self%IROT=mod(kgds(6)/8,2)
52 self%IM=kgds(2)
53 self%JM=kgds(3)
54
55 slat1=sin(rlat1/dpr)
56 clat1=cos(rlat1/dpr)
57 self%SLAT0=sin(rlat0/dpr)
58 self%CLAT0=cos(rlat0/dpr)
59
60 hs=sign(1._kd,mod(rlon1-self%RLON0+180+3600,360._kd)-180)
61 clon1=cos((rlon1-self%RLON0)/dpr)
62 slatr=self%CLAT0*slat1-self%SLAT0*clat1*clon1
63 clatr=sqrt(1-slatr**2)
64 clonr=(self%CLAT0*clat1*clon1+self%SLAT0*slat1)/clatr
65 rlatr=dpr*asin(slatr)
66 rlonr=hs*dpr*acos(clonr)
67
68 self%WBD=rlonr
69 self%SBD=rlatr
70 slat2=sin(rlat2/dpr)
71 clat2=cos(rlat2/dpr)
72 hs2=sign(1._kd,mod(rlon2-self%RLON0+180+3600,360._kd)-180)
73 clon2=cos((rlon2-self%RLON0)/dpr)
74 slatr=self%CLAT0*slat2-self%SLAT0*clat2*clon2
75 clatr=sqrt(1-slatr**2)
76 clonr=(self%CLAT0*clat2*clon2+self%SLAT0*slat2)/clatr
77 nbd=dpr*asin(slatr)
78 ebd=hs2*dpr*acos(clonr)
79 self%DLATS=(nbd-self%SBD)/float(self%JM-1)
80 self%DLONS=(ebd-self%WBD)/float(self%IM-1)
81
82 self%iwrap = 0
83 self%jwrap1 = 0
84 self%jwrap2 = 0
85 self%nscan = mod(kgds(11) / 32, 2)
86 self%nscan_field_pos = self%nscan
87 self%kscan = 0
88 end associate
89
90 end subroutine init_grib1
91
92 subroutine init_grib2(self, g2_desc)
93 class(ip_rot_equid_cylind_grid), intent(inout) :: self
94 type(grib2_descriptor), intent(in) :: g2_desc
95
96 real(kd) :: rlat1, rlon1, rlat0, rlat2, rlon2, nbd, ebd
97 integer :: iscale
98 integer :: i_offset_odd, i_offset_even, j_offset
99
100 associate(igdtmpl => g2_desc%gdt_tmpl, igdtlen => g2_desc%gdt_len)
101
102 CALL earth_radius(igdtmpl,igdtlen,self%rerth,self%eccen_squared)
103
104 i_offset_odd=mod(igdtmpl(19)/8,2)
105 i_offset_even=mod(igdtmpl(19)/4,2)
106 j_offset=mod(igdtmpl(19)/2,2)
107
108 iscale=igdtmpl(10)*igdtmpl(11)
109 IF(iscale==0) iscale=10**6
110
111 rlat1=float(igdtmpl(12))/float(iscale)
112 rlon1=float(igdtmpl(13))/float(iscale)
113 rlat0=float(igdtmpl(20))/float(iscale)
114 rlat0=rlat0+90.0_kd
115
116 self%RLON0=float(igdtmpl(21))/float(iscale)
117
118 rlat2=float(igdtmpl(15))/float(iscale)
119 rlon2=float(igdtmpl(16))/float(iscale)
120
121 self%IROT=mod(igdtmpl(14)/8,2)
122 self%IM=igdtmpl(8)
123 self%JM=igdtmpl(9)
124
125 self%SLAT0=sin(rlat0/dpr)
126 self%CLAT0=cos(rlat0/dpr)
127
128 self%WBD=rlon1
129 IF (self%WBD > 180.0) self%WBD = self%WBD - 360.0
130 self%SBD=rlat1
131
132 nbd=rlat2
133 ebd=rlon2
134
135 self%DLATS=(nbd-self%SBD)/float(self%JM-1)
136 self%DLONS=(ebd-self%WBD)/float(self%IM-1)
137
138 IF(i_offset_odd==1) self%WBD=self%WBD+(0.5_kd*self%DLONS)
139 IF(j_offset==1) self%SBD=self%SBD+(0.5_kd*self%DLATS)
140
141 self%iwrap = 0
142 self%jwrap1 = 0
143 self%jwrap2 = 0
144 self%kscan = 0
145 self%nscan = mod(igdtmpl(19) / 32, 2)
146 self%nscan_field_pos = self%nscan
147 end associate
148 end subroutine init_grib2
149
150
151
152 SUBROUTINE gdswzd_rot_equid_cylind(self,IOPT,NPTS, &
153 FILL,XPTS,YPTS,RLON,RLAT,NRET, &
154 CROT,SROT,XLON,XLAT,YLON,YLAT,AREA)
155 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
156 !
157 ! SUBPROGRAM: GDSWZD_ROT_EQUID_CYLIND GDS WIZARD FOR ROTATED
158 ! EQUIDISTANT CYLINDRICAL
159 ! PRGMMR: GAYNO ORG: W/NMC23 DATE: 2007-NOV-15
160 !
161 ! ABSTRACT: THIS SUBPROGRAM DECODES THE GRIB 2 GRID DEFINITION
162 ! TEMPLATE (PASSED IN INTEGER FORM AS DECODED BY THE
163 ! NCEP G2 LIBRARY) AND RETURNS ONE OF THE FOLLOWING:
164 ! (IOPT=+1) EARTH COORDINATES OF SELECTED GRID COORDINATES
165 ! (IOPT=-1) GRID COORDINATES OF SELECTED EARTH COORDINATES
166 ! WORKS FOR NON-"E" STAGGERED ROTATED EQUIDISTANT CYLINDRICAL
167 ! PROJECTIONS. THE SCAN MODE (SECTION 3, OCTET 72, BITS 5-6)
168 ! DETERMINE WHETHER THIS IS AN "H" OR "V" GRID. IF
169 ! THE SELECTED COORDINATES ARE MORE THAN ONE GRIDPOINT
170 ! BEYOND THE THE EDGES OF THE GRID DOMAIN, THEN THE RELEVANT
171 ! OUTPUT ELEMENTS ARE SET TO FILL VALUES. THE ACTUAL
172 ! NUMBER OF VALID POINTS COMPUTED IS RETURNED TOO.
173 ! OPTIONALLY, THE VECTOR ROTATIONS, THE MAP JACOBIANS AND
174 ! THE GRID BOX AREAS MAY BE RETURNED AS WELL. TO COMPUTE
175 ! THE VECTOR ROTATIONS, THE OPTIONAL ARGUMENTS 'SROT' AND 'CROT'
176 ! MUST BE PRESENT. TO COMPUTE THE MAP JACOBIANS, THE
177 ! OPTIONAL ARGUMENTS 'XLON', 'XLAT', 'YLON', 'YLAT' MUST
178 ! BE PRESENT. TO COMPUTE THE GRID BOX AREAS, THE OPTIONAL
179 ! ARGUMENT 'AREA' MUST BE PRESENT.
180 !
181 ! PROGRAM HISTORY LOG:
182 ! 2010-JAN-15 GAYNO BASED ON ROUTINES GDSWZDCB AND GDSWZDCA
183 ! 2015-JAN-21 GAYNO MERGER OF GDSWIZCD AND GDSWZDCD. MAKE
184 ! CROT,SORT,XLON,XLAT,YLON,YLAT AND AREA
185 ! OPTIONAL ARGUMENTS. MAKE PART OF A MODULE.
186 ! MOVE VECTOR ROTATION, MAP JACOBIAN AND GRID
187 ! BOX AREA COMPUTATIONS TO SEPARATE SUBROUTINES.
188 ! 2015-JUL-13 GAYNO CONVERT TO GRIB 2. REPLACE GRIB 1 KGDS ARRAY
189 ! WITH GRIB 2 GRID DEFINITION TEMPLATE ARRAY.
190 ! RENAME AS "GDSWZD_ROT_EQUID_CYLIND."
191 ! 2018-07-20 WESLEY ADD THREADS.
192 !
193 ! USAGE: CALL GDSWZD_ROT_EQUID_CYLIND(IGDTNUM,IGDTMPL,IGDTLEN,IOPT,NPTS,
194 ! & FILL,XPTS,YPTS,RLON,RLAT,NRET,
195 ! & CROT,SROT,XLON,XLAT,YLON,YLAT,AREA)
196 !
197 ! INPUT ARGUMENT LIST:
198 ! IGDTNUM - INTEGER GRID DEFINITION TEMPLATE NUMBER.
199 ! CORRESPONDS TO THE GFLD%IGDTNUM COMPONENT OF THE
200 ! NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
201 ! IGDTMPL - INTEGER (IGDTLEN) GRID DEFINITION TEMPLATE ARRAY.
202 ! CORRESPONDS TO THE GFLD%IGDTMPL COMPONENT OF THE
203 ! NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE FOR SECTION
204 ! THREE:
205 ! (1): SHAPE OF EARTH, OCTET 15
206 ! (2): SCALE FACTOR OF SPHERICAL EARTH RADIUS,
207 ! OCTET 16
208 ! (3): SCALED VALUE OF RADIUS OF SPHERICAL EARTH,
209 ! OCTETS 17-20
210 ! (4): SCALE FACTOR OF MAJOR AXIS OF ELLIPTICAL EARTH,
211 ! OCTET 21
212 ! (5): SCALED VALUE OF MAJOR AXIS OF ELLIPTICAL EARTH,
213 ! OCTETS 22-25
214 ! (6): SCALE FACTOR OF MINOR AXIS OF ELLIPTICAL EARTH,
215 ! OCTET 26
216 ! (7): SCALED VALUE OF MINOR AXIS OF ELLIPTICAL EARTH,
217 ! OCTETS 27-30
218 ! (8): NUMBER OF POINTS ALONG A PARALLEL, OCTS 31-34
219 ! (9): NUMBER OF POINTS ALONG A MERIDIAN, OCTS 35-38
220 ! (10): BASIC ANGLE OF INITIAL PRODUCTION DOMAIN,
221 ! OCTETS 39-42
222 ! (11): SUBDIVISIONS OF BASIC ANGLE, OCTETS 43-46
223 ! (12): LATITUDE OF FIRST GRID POINT IN X/Y SPACE
224 ! (BEFORE ROTATION), OCTETS 47-50
225 ! (13): LONGITUDE OF FIRST GRID POINT IN X/Y
226 ! SPACE (BEFORE ROTATION), OCTETS 51-54
227 ! (14): RESOLUTION AND COMPONENT FLAGS, OCTET 55
228 ! (15): LATITUDE OF LAST GRID POINT IN X/Y SPACE
229 ! (BEFORE ROTATION), OCTETS 56-59
230 ! (16): LONGITUDE OF LAST GRID POINT IN X/Y SPACE
231 ! (BEFORE ROTATION), OCTETS 60-63
232 ! (17): I-DIRECTION INCREMENT, OCTETS 64-67
233 ! (18): J-DIRECTION INCREMENT, OCTETS 68-71
234 ! (19): SCANNING MODE, OCTET 72
235 ! (20): LATITUDE OF SOUTHERN POLE OF PROJECTION,
236 ! OCTETS 73-76
237 ! (21): LONGITUDE OF SOUTHERN POLE OF PROJECTION,
238 ! OCTETS 77-80
239 ! (22): ANGLE OF ROTATION OF PROJECTION, OCTS 81-84
240 ! IGDTLEN - INTEGER NUMBER OF ELEMENTS (22) OF THE GRID DEFINITION
241 ! TEMPLATE ARRAY. CORRESPONDS TO THE GFLD%IGDTLEN
242 ! COMPONENT OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
243 ! IOPT - INTEGER OPTION FLAG
244 ! (+1 TO COMPUTE EARTH COORDS OF SELECTED GRID COORDS)
245 ! (-1 TO COMPUTE GRID COORDS OF SELECTED EARTH COORDS)
246 ! NPTS - INTEGER MAXIMUM NUMBER OF COORDINATES
247 ! FILL - REAL FILL VALUE TO SET INVALID OUTPUT DATA
248 ! (MUST BE IMPOSSIBLE VALUE; SUGGESTED VALUE: -9999.)
249 ! XPTS - REAL (NPTS) GRID X POINT COORDINATES IF IOPT>0
250 ! YPTS - REAL (NPTS) GRID Y POINT COORDINATES IF IOPT>0
251 ! RLON - REAL (NPTS) EARTH LONGITUDES IN DEGREES E IF IOPT<0
252 ! (ACCEPTABLE RANGE: -360. TO 360.)
253 ! RLAT - REAL (NPTS) EARTH LATITUDES IN DEGREES N IF IOPT<0
254 ! (ACCEPTABLE RANGE: -90. TO 90.)
255 !
256 ! OUTPUT ARGUMENT LIST:
257 ! XPTS - REAL (NPTS) GRID X POINT COORDINATES IF IOPT<0
258 ! YPTS - REAL (NPTS) GRID Y POINT COORDINATES IF IOPT<0
259 ! RLON - REAL (NPTS) EARTH LONGITUDES IN DEGREES E IF IOPT>0
260 ! RLAT - REAL (NPTS) EARTH LATITUDES IN DEGREES N IF IOPT>0
261 ! NRET - INTEGER NUMBER OF VALID POINTS COMPUTED
262 ! CROT - REAL, OPTIONAL (NPTS) CLOCKWISE VECTOR ROTATION COSINES
263 ! SROT - REAL, OPTIONAL (NPTS) CLOCKWISE VECTOR ROTATION SINES
264 ! (UGRID=CROT*UEARTH-SROT*VEARTH;
265 ! VGRID=SROT*UEARTH+CROT*VEARTH)
266 ! XLON - REAL, OPTIONAL (NPTS) DX/DLON IN 1/DEGREES
267 ! XLAT - REAL, OPTIONAL (NPTS) DX/DLAT IN 1/DEGREES
268 ! YLON - REAL, OPTIONAL (NPTS) DY/DLON IN 1/DEGREES
269 ! YLAT - REAL, OPTIONAL (NPTS) DY/DLAT IN 1/DEGREES
270 ! AREA - REAL, OPTIONAL (NPTS) AREA WEIGHTS IN M**2
271 !
272 ! ATTRIBUTES:
273 ! LANGUAGE: FORTRAN 90
274 !
275 !$$$
276 IMPLICIT NONE
277
278 class(ip_rot_equid_cylind_grid), intent(in) :: self
279 INTEGER, INTENT(IN ) :: IOPT, NPTS
280 INTEGER, INTENT( OUT) :: NRET
281 !
282 REAL, INTENT(IN ) :: FILL
283 REAL, INTENT(INOUT) :: RLON(NPTS),RLAT(NPTS)
284 REAL, INTENT(INOUT) :: XPTS(NPTS),YPTS(NPTS)
285 REAL, OPTIONAL, INTENT( OUT) :: CROT(NPTS),SROT(NPTS)
286 REAL, OPTIONAL, INTENT( OUT) :: XLON(NPTS),XLAT(NPTS)
287 REAL, OPTIONAL, INTENT( OUT) :: YLON(NPTS),YLAT(NPTS),AREA(NPTS)
288 !
289 INTEGER :: IM,JM,N
290 !
291 LOGICAL :: LROT, LMAP, LAREA
292 !
293 REAL :: DUM1,DUM2
294 REAL(KIND=kd) :: hs
295 REAL(KIND=kd) :: clonr,clatr,slatr
296 REAL(KIND=kd) :: clat,slat,clon
297 REAL(KIND=kd) :: rlatr,rlonr
298 REAL(KIND=kd) :: wbd,sbd
299 REAL :: XMIN,XMAX,YMIN,YMAX
300 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
301 IF(PRESENT(crot)) crot=fill
302 IF(PRESENT(srot)) srot=fill
303 IF(PRESENT(xlon)) xlon=fill
304 IF(PRESENT(xlat)) xlat=fill
305 IF(PRESENT(ylon)) ylon=fill
306 IF(PRESENT(ylat)) ylat=fill
307 IF(PRESENT(area)) area=fill
308 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
309 ! IS THE EARTH RADIUS DEFINED?
310 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
311 ! IS THIS AN "E"-STAGGER GRID? ROUTINE CAN'T PROCESS THOSE.
312 ! I_OFFSET_ODD=MOD(IGDTMPL(19)/8,2)
313 ! I_OFFSET_EVEN=MOD(IGDTMPL(19)/4,2)
314 ! J_OFFSET=MOD(IGDTMPL(19)/2,2)
315 ! IF(I_OFFSET_ODD/=I_OFFSET_EVEN) THEN
316 ! CALL ROT_EQUID_CYLIND_ERROR(IOPT,FILL,RLAT,RLON,XPTS,YPTS,NPTS)
317 ! RETURN
318 ! ENDIF
319 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
320
321
322 rlon0=self%rlon0
323 irot=self%irot
324
325 im=self%im
326 jm=self%jm
327
328 slat0=self%slat0
329 clat0=self%clat0
330
331 wbd=self%wbd
332 sbd=self%sbd
333
334 dlats=self%dlats
335 dlons=self%dlons
336
337 xmin=0
338 xmax=im+1
339 ymin=0
340 ymax=jm+1
341 nret=0
342
343 rerth = self%rerth
344 IF(rerth<0.)THEN
345 CALL rot_equid_cylind_error(iopt,fill,rlat,rlon,xpts,ypts,npts)
346 RETURN
347 ENDIF
348
349 IF(PRESENT(crot).AND.PRESENT(srot))THEN
350 lrot=.true.
351 ELSE
352 lrot=.false.
353 ENDIF
354 IF(PRESENT(xlon).AND.PRESENT(xlat).AND.PRESENT(ylon).AND.PRESENT(ylat))THEN
355 lmap=.true.
356 ELSE
357 lmap=.false.
358 ENDIF
359 IF(PRESENT(area))THEN
360 larea=.true.
361 ELSE
362 larea=.false.
363 ENDIF
364 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
365 ! TRANSLATE GRID COORDINATES TO EARTH COORDINATES
366 IF(iopt.EQ.0.OR.iopt.EQ.1) THEN
367 !$OMP PARALLEL DO PRIVATE(N,RLONR,RLATR,HS,CLONR,SLATR,CLATR,SLAT,CLAT,CLON) &
368 !$OMP& REDUCTION(+:NRET) SCHEDULE(STATIC)
369 DO n=1,npts
370 IF(xpts(n).GE.xmin.AND.xpts(n).LE.xmax.AND. &
371 ypts(n).GE.ymin.AND.ypts(n).LE.ymax) THEN
372 rlonr=wbd+(xpts(n)-1._kd)*dlons
373 rlatr=sbd+(ypts(n)-1._kd)*dlats
374 IF(rlonr <= 0._kd) THEN
375 hs=-1.0_kd
376 ELSE
377 hs=1.0_kd
378 ENDIF
379 clonr=cos(rlonr/dpr)
380 slatr=sin(rlatr/dpr)
381 clatr=cos(rlatr/dpr)
382 slat=clat0*slatr+slat0*clatr*clonr
383 IF(slat.LE.-1) THEN
384 clat=0.
385 clon=cos(rlon0/dpr)
386 rlon(n)=0.
387 rlat(n)=-90.
388 ELSEIF(slat.GE.1) THEN
389 clat=0.
390 clon=cos(rlon0/dpr)
391 rlon(n)=0.
392 rlat(n)=90.
393 ELSE
394 clat=sqrt(1-slat**2)
395 clon=(clat0*clatr*clonr-slat0*slatr)/clat
396 clon=min(max(clon,-1._kd),1._kd)
397 rlon(n)=mod(rlon0+hs*dpr*acos(clon)+3600,360._kd)
398 rlat(n)=dpr*asin(slat)
399 ENDIF
400 nret=nret+1
401 IF(lrot) CALL rot_equid_cylind_vect_rot(rlon(n), clatr, slatr, &
402 clat, slat, clon, crot(n), srot(n))
403 IF(lmap) CALL rot_equid_cylind_map_jacob(fill, rlon(n), clatr, &
404 clat, slat, clon, xlon(n), xlat(n), ylon(n), ylat(n))
405 IF(larea) CALL rot_equid_cylind_grid_area(clatr, fill, area(n))
406 ELSE
407 rlon(n)=fill
408 rlat(n)=fill
409 ENDIF
410 ENDDO
411 !$OMP END PARALLEL DO
412 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
413 ! TRANSLATE EARTH COORDINATES TO GRID COORDINATES
414 ELSEIF(iopt.EQ.-1) THEN
415 !$OMP PARALLEL DO PRIVATE(N,HS,CLON,SLAT,CLAT,SLATR,CLATR,CLONR,RLONR,RLATR) &
416 !$OMP& REDUCTION(+:NRET) SCHEDULE(STATIC)
417 DO n=1,npts
418 IF(abs(rlon(n)).LE.360.AND.abs(rlat(n)).LE.90) THEN
419 hs=sign(1._kd,mod(rlon(n)-rlon0+180+3600,360._kd)-180)
420 clon=cos((rlon(n)-rlon0)/dpr)
421 slat=sin(rlat(n)/dpr)
422 clat=cos(rlat(n)/dpr)
423 slatr=clat0*slat-slat0*clat*clon
424 IF(slatr.LE.-1) THEN
425 clatr=0._kd
426 rlonr=0.
427 rlatr=-90.
428 ELSEIF(slatr.GE.1) THEN
429 clatr=0._kd
430 rlonr=0.
431 rlatr=90.
432 ELSE
433 clatr=sqrt(1-slatr**2)
434 clonr=(clat0*clat*clon+slat0*slat)/clatr
435 clonr=min(max(clonr,-1._kd),1._kd)
436 rlonr=hs*dpr*acos(clonr)
437 rlatr=dpr*asin(slatr)
438 ENDIF
439 xpts(n)=(rlonr-wbd)/dlons+1._kd
440 ypts(n)=(rlatr-sbd)/dlats+1._kd
441 IF(xpts(n).GE.xmin.AND.xpts(n).LE.xmax.AND. &
442 ypts(n).GE.ymin.AND.ypts(n).LE.ymax) THEN
443 nret=nret+1
444 IF(lrot) CALL rot_equid_cylind_vect_rot(rlon(n), clatr, slatr, &
445 clat, slat, clon, crot(n), srot(n))
446 IF(lmap) CALL rot_equid_cylind_map_jacob(fill, rlon(n), clatr, &
447 clat, slat, clon, xlon(n), xlat(n), ylon(n), ylat(n))
448 IF(larea) CALL rot_equid_cylind_grid_area(clatr, fill, area(n))
449 ELSE
450 xpts(n)=fill
451 ypts(n)=fill
452 ENDIF
453 ELSE
454 xpts(n)=fill
455 ypts(n)=fill
456 ENDIF
457 ENDDO
458 !$OMP END PARALLEL DO
459 ENDIF
460 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
461 END SUBROUTINE gdswzd_rot_equid_cylind
462 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
463 SUBROUTINE rot_equid_cylind_error(IOPT,FILL,RLAT,RLON,XPTS,YPTS,NPTS)
464 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
465 !
466 ! SUBPROGRAM: ROT_EQUID_CYLIND_ERROR ERROR HANDLER
467 ! PRGMMR: GAYNO ORG: W/NMC23 DATE: 2015-07-13
468 !
469 ! ABSTRACT: UPON AN ERROR, THIS SUBPROGRAM ASSIGNS
470 ! A "FILL" VALUE TO THE OUTPUT FIELDS.
471 !
472 ! PROGRAM HISTORY LOG:
473 ! 2015-07-13 GAYNO INITIAL VERSION
474 !
475 ! USAGE: CALL ROT_EQUID_CYLIND_ERROR(IOPT,FILL,RLAT,RLON,XPTS,YPTS,NPTS)
476 !
477 ! INPUT ARGUMENT LIST:
478 ! IOPT - INTEGER OPTION FLAG
479 ! (+1 TO COMPUTE EARTH COORDS OF SELECTED GRID COORDS)
480 ! (-1 TO COMPUTE GRID COORDS OF SELECTED EARTH COORDS)
481 ! NPTS - INTEGER MAXIMUM NUMBER OF COORDINATES
482 ! FILL - REAL FILL VALUE TO SET INVALID OUTPUT DATA
483 ! (MUST BE IMPOSSIBLE VALUE; SUGGESTED VALUE: -9999.)
484 ! OUTPUT ARGUMENT LIST:
485 ! RLON - REAL (NPTS) EARTH LONGITUDES IN DEGREES E IF IOPT<0
486 ! RLAT - REAL (NPTS) EARTH LATITUDES IN DEGREES N IF IOPT<0
487 ! XPTS - REAL (NPTS) GRID X POINT COORDINATES IF IOPT>0
488 ! YPTS - REAL (NPTS) GRID Y POINT COORDINATES IF IOPT>0
489 !
490 ! ATTRIBUTES:
491 ! LANGUAGE: FORTRAN 90
492 !
493 !$$$
494 IMPLICIT NONE
495 !
496 INTEGER, INTENT(IN ) :: IOPT, NPTS
497 !
498 REAL, INTENT(IN ) :: FILL
499 REAL, INTENT( OUT) :: RLAT(NPTS),RLON(NPTS)
500 REAL, INTENT( OUT) :: XPTS(NPTS),YPTS(NPTS)
501 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
502 IF(iopt>=0) THEN
503 rlon=fill
504 rlat=fill
505 ENDIF
506 IF(iopt<=0) THEN
507 xpts=fill
508 ypts=fill
509 ENDIF
510 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511 END SUBROUTINE rot_equid_cylind_error
512 !
513 SUBROUTINE rot_equid_cylind_vect_rot(RLON, CLATR, SLATR, CLAT, SLAT, &
514 CLON, CROT, SROT)
515 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
516 !
517 ! SUBPROGRAM: ROT_EQUID_CYLIND_VECT_ROT VECTOR ROTATION FIELDS FOR
518 ! ROTATED EQUIDISTANT CYLINDRICAL
519 ! GRIDS - NON "E" STAGGER.
520 !
521 ! PRGMMR: GAYNO ORG: W/NMC23 DATE: 2015-01-21
522 !
523 ! ABSTRACT: THIS SUBPROGRAM COMPUTES THE VECTOR ROTATION SINES AND
524 ! COSINES FOR A ROTATED EQUIDISTANT CYLINDRICAL GRID -
525 ! NON "E" STAGGER.
526 !
527 ! PROGRAM HISTORY LOG:
528 ! 2015-01-21 GAYNO INITIAL VERSION
529 ! 2015-07-19 GAYNO RENAME AS "ROT_EQUID_CYLIND_VECT_ROT."
530 ! 2018-07-20 WESLEY PASS IN CLATR, SLATR, CLAT, SLAT, CLON
531 ! FOR THREADING.
532 !
533 ! USAGE: CALL ROT_EQUID_CYLIND_VECT_ROT(RLON, CLATR, SLATR, CLAT, SLAT, &
534 ! CLON, CROT, SROT)
535 !
536 ! INPUT ARGUMENT LIST:
537 ! RLON - LONGITUDE IN DEGREES (REAL)
538 ! CLATR - COSINE OF ROTATED LATITUDE (REAL)
539 ! SLATR - SINE OF ROTATED LATITUDE (REAL)
540 ! CLAT - COSINE OF LATITUDE (REAL)
541 ! SLAT - SINE OF LATITUDE (REAL)
542 ! CLON - COSINE OF LONGITUDE (REAL)
543 !
544 ! OUTPUT ARGUMENT LIST:
545 ! CROT - CLOCKWISE VECTOR ROTATION COSINES (REAL)
546 ! SROT - CLOCKWISE VECTOR ROTATION SINES (REAL)
547 ! (UGRID=CROT*UEARTH-SROT*VEARTH;
548 ! VGRID=SROT*UEARTH+CROT*VEARTH)
549 !
550 ! ATTRIBUTES:
551 ! LANGUAGE: FORTRAN 90
552 !
553 !$$$
554 !
555 IMPLICIT NONE
556
557 REAL(KIND=kd), INTENT(IN ) :: clat, clatr, clon, slat, slatr
558 REAL , INTENT(IN ) :: RLON
559 REAL , INTENT( OUT) :: CROT, SROT
560
561 REAL(KIND=kd) :: slon
562
563 IF(irot.EQ.1) THEN
564 IF(clatr.LE.0._kd) THEN
565 crot=-sign(1._kd,slatr*slat0)
566 srot=0.
567 ELSE
568 slon=sin((rlon-rlon0)/dpr)
569 crot=(clat0*clat+slat0*slat*clon)/clatr
570 srot=slat0*slon/clatr
571 ENDIF
572 ELSE
573 crot=1.
574 srot=0.
575 ENDIF
576
577 END SUBROUTINE rot_equid_cylind_vect_rot
578 !
579 SUBROUTINE rot_equid_cylind_map_jacob(FILL, RLON, CLATR, CLAT, &
580 SLAT, CLON, XLON, XLAT, YLON, YLAT)
581 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
582 !
583 ! SUBPROGRAM: ROT_EQUID_CYLIND_MAP_JACOB
584 ! MAP JACOBIANS FOR ROTATED EQUIDISTANT CYLINDRICAL
585 ! GRIDS - NON "E" STAGGER.
586 !
587 ! PRGMMR: GAYNO ORG: W/NMC23 DATE: 2015-01-21
588 !
589 ! ABSTRACT: THIS SUBPROGRAM COMPUTES THE MAP JACOBIANS FOR
590 ! A ROTATED EQUIDISTANT CYLINDRICAL GRID -
591 ! NON "E" STAGGER.
592 !
593 ! PROGRAM HISTORY LOG:
594 ! 2015-01-21 GAYNO INITIAL VERSION
595 ! 2015-09-17 GAYNO RENAME AS "ROT_EQUID_CYLIND_MAP_JACOB".
596 ! 2018-07-20 WESLEY PASS IN CLATR, CLAT, SLAT, CLON TO ALLOW
597 ! THREADING.
598 !
599 ! USAGE: CALL ROT_EQUID_CYLIND_MAP_JACOB(FILL, RLON, CLATR, CLAT, &
600 ! SLAT, CLON, XLON, XLAT, YLON, YLAT)
601 !
602 ! INPUT ARGUMENT LIST:
603 ! CLATR - COSINE OF UNROTATED LATITUDE (REAL)
604 ! CLAT - COSINE OF LATITUDE (REAL)
605 ! SLAT - SINE OF LATITUDE (REAL)
606 ! CLON - COSINE OF LATITUDE (REAL)
607 ! FILL - FILL VALUE FOR UNDEFINED POINTS (REAL)
608 ! RLON - LONGITUDE IN DEGREES (REAL)
609 !
610 ! OUTPUT ARGUMENT LIST:
611 ! XLON - DX/DLON IN 1/DEGREES (REAL)
612 ! XLAT - DX/DLAT IN 1/DEGREES (REAL)
613 ! YLON - DY/DLON IN 1/DEGREES (REAL)
614 ! YLAT - DY/DLAT IN 1/DEGREES (REAL)
615 !
616 ! ATTRIBUTES:
617 ! LANGUAGE: FORTRAN 90
618 !
619 !$$$
620 !
621 IMPLICIT NONE
622
623 REAL(KIND=kd), INTENT(IN ) :: clatr, clat, slat, clon
624 REAL , INTENT(IN ) :: FILL, RLON
625 REAL , INTENT( OUT) :: XLON, XLAT, YLON, YLAT
626
627 REAL(KIND=kd) :: slon, term1, term2
628
629 IF(clatr.LE.0._kd) THEN
630 xlon=fill
631 xlat=fill
632 ylon=fill
633 ylat=fill
634 ELSE
635 slon=sin((rlon-rlon0)/dpr)
636 term1=(clat0*clat+slat0*slat*clon)/clatr
637 term2=slat0*slon/clatr
638 xlon=term1*clat/(dlons*clatr)
639 xlat=-term2/(dlons*clatr)
640 ylon=term2*clat/dlats
641 ylat=term1/dlats
642 ENDIF
643
644 END SUBROUTINE rot_equid_cylind_map_jacob
645 !
646 SUBROUTINE rot_equid_cylind_grid_area(CLATR, FILL, AREA)
647 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
648 !
649 ! SUBPROGRAM: ROT_EQUID_CYLIND_GRID_AREA GRID BOX AREA FOR
650 ! ROTATED EQUIDISTANT CYLINDRICAL
651 ! GRIDS - NON "E" STAGGER.
652 !
653 ! PRGMMR: GAYNO ORG: W/NMC23 DATE: 2015-01-21
654 !
655 ! ABSTRACT: THIS SUBPROGRAM COMPUTES THE GRID BOX AREA FOR
656 ! A ROTATED EQUIDISTANT CYLINDRICAL GRID -
657 ! NON "E" STAGGER.
658 !
659 ! PROGRAM HISTORY LOG:
660 ! 2015-01-21 GAYNO INITIAL VERSION
661 ! 2015-07-19 GAYNO RENAME AS "ROT_EQUID_CYLIND_GRID_AREA."
662 ! 2018-07-20 WESLEY PASS IN CLATR FOR THREADING
663 !
664 ! USAGE: CALL ROT_EQUID_CYLIND_GRID_AREA(FILL,AREA,CLATR)
665 !
666 ! INPUT ARGUMENT LIST:
667 ! CLATR - COSINE OF UNROTATED LATITUDE (REAL)
668 ! FILL - FILL VALUE FOR UNDEFINED POINTS (REAL)
669 !
670 ! OUTPUT ARGUMENT LIST:
671 ! AREA - AREA WEIGHTS IN M**2 (REAL)
672 !
673 ! ATTRIBUTES:
674 ! LANGUAGE: FORTRAN 90
675 !
676 !$$$
677 !
678 IMPLICIT NONE
679
680 REAL(KIND=kd), INTENT(IN ) :: clatr
681 REAL, INTENT(IN ) :: FILL
682 REAL, INTENT( OUT) :: AREA
683
684 IF(clatr.LE.0._kd) THEN
685 area=fill
686 ELSE
687 area=2._kd*(rerth**2)*clatr*(dlons/dpr)*sin(0.5_kd*dlats/dpr)
688 ENDIF
689
690 END SUBROUTINE rot_equid_cylind_grid_area
691
692end module ip_rot_equid_cylind_grid_mod
693
Module containing common constants.
real(real64), parameter pi
PI.
real(real64), parameter dpr
Radians to degrees.
Uses derived type grid descriptor objects to abstract away the raw Grib-1 and Grib-2 grid definitions...
Abstract ip_grid type.
Definition: ip_grid_mod.f90:8
Abstract grid that holds fields and methods common to all grids.
Definition: ip_grid_mod.f90:45