NCEPLIBS-ip 5.2.0
Loading...
Searching...
No Matches
ip_rot_equid_cylind_egrid_mod.F90
Go to the documentation of this file.
1
7
25 use iso_fortran_env, only: real64
27 use ip_grid_mod
28 use ip_constants_mod, only: dpr, pi
30 implicit none
31
32 private
34
35 integer, parameter :: kd = real64
36
38 real(kd) :: rlon0
39 real(kd) :: rlon1
40 real(kd) :: rlat1
41 real(kd) :: clat0
42 real(kd) :: slat0
43 real(kd) :: dlats
44 real(kd) :: dlons
45 real(kd) :: hi
49 integer :: irot
50 contains
54 procedure :: init_grib1
58 procedure :: init_grib2
64
65 INTEGER :: irot
66
67 REAL(kind=kd) :: clat
68 REAL(kind=kd) :: clat0
69 REAL(kind=kd) :: clatr
70 REAL(kind=kd) :: clon
71 REAL(kind=kd) :: dlats
72 REAL(kind=kd) :: dlons
73 REAL(kind=kd) :: rerth
74 REAL(kind=kd) :: rlon0
75 REAL(kind=kd) :: slat
76 REAL(kind=kd) :: slat0
77 REAL(kind=kd) :: slatr
78
79contains
80
89 subroutine init_grib1(self, g1_desc)
90 class(ip_rot_equid_cylind_egrid), intent(inout) :: self
91 type(grib1_descriptor), intent(in) :: g1_desc
92
93 integer :: iscan
94 real(kd) :: rlat0
95
96 real(kd) :: rlat1, rlon1, rlon0, slat1, clat1, slat0, clat0, clon1
97 real(kd) :: slatr, clatr, clonr, rlatr, rlonr, dlats, dlons, hs, hi
98 integer :: im, jm
99
100 integer :: is1, kscan, irot
101
102 associate(kgds => g1_desc%gds)
103 self%rerth = 6.3712e6_kd
104 self%eccen_squared = 0.0
105
106 im=kgds(2)
107 jm=kgds(3)
108
109 self%nscan_field_pos = 3
110 self%nscan = mod(kgds(11)/32,2)
111
112 rlat1=kgds(4)*1.e-3_kd
113 rlon1=kgds(5)*1.e-3_kd
114 rlat0=kgds(7)*1.e-3_kd
115 rlon0=kgds(8)*1.e-3_kd
116
117 irot=mod(kgds(6)/8,2)
118 kscan=mod(kgds(11)/256,2)
119 iscan=mod(kgds(11)/128,2)
120 hi=(-1.)**iscan
121 slat1=sin(rlat1/dpr)
122 clat1=cos(rlat1/dpr)
123 slat0=sin(rlat0/dpr)
124 clat0=cos(rlat0/dpr)
125 hs=sign(1._kd,mod(rlon1-rlon0+180+3600,360._kd)-180)
126 clon1=cos((rlon1-rlon0)/dpr)
127 slatr=clat0*slat1-slat0*clat1*clon1
128 clatr=sqrt(1-slatr**2)
129 clonr=(clat0*clat1*clon1+slat0*slat1)/clatr
130 rlatr=dpr*asin(slatr)
131 rlonr=hs*dpr*acos(clonr)
132 dlats=rlatr/(-(jm-1)/2)
133 dlons=rlonr/(-((im * 2 - 1) -1)/2)
134
135 IF(kscan.EQ.0) THEN
136 is1=(jm+1)/2
137 ELSE
138 is1=jm/2
139 ENDIF
140
141 self%im = im
142 self%jm = jm
143 self%rlon0 = rlon0
144 self%rlon1 = rlon1
145 self%rlat1 = rlat1
146 self%clat0 = clat0
147 self%slat0 = slat0
148 self%dlats = dlats
149 self%dlons = dlons
150 self%hi = hi
151 self%irot = irot
152 self%kscan = kscan
153
154
155 end associate
156
157 end subroutine init_grib1
158
159
166 subroutine init_grib2(self, g2_desc)
167 class(ip_rot_equid_cylind_egrid), intent(inout) :: self
168 type(grib2_descriptor), intent(in) :: g2_desc
169
170 integer :: iscale, iscan
171 real(kd) :: rlat0
172 integer :: i_offset_odd!, i_offset_even
173
174 associate(igdtmpl => g2_desc%gdt_tmpl, igdtlen => g2_desc%gdt_len)
175 CALL earth_radius(igdtmpl,igdtlen,self%rerth,self%eccen_squared)
176
177 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
178 ! ROUTINE ONLY WORKS FOR "E"-STAGGER GRIDS.
179 ! "V" GRID WHEN BIT 5 IS '1' AND BIT 6 IS '0'.
180 ! "H" GRID WHEN BIT 5 IS '0' AND BIT 6 IS '1'.
181 ! I_OFFSET_ODD=MOD(IGDTMPL(19)/8,2)
182 ! I_OFFSET_EVEN=MOD(IGDTMPL(19)/4,2)
183 ! IF(I_OFFSET_ODD==I_OFFSET_EVEN) THEN
184 ! CALL ROT_EQUID_CYLIND_EGRID_ERROR(IOPT,FILL,RLAT,RLON,XPTS,YPTS,NPTS)
185 ! RETURN
186 ! ENDIF
187 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
188
189 self%IM=igdtmpl(8)
190 self%JM=igdtmpl(9)
191
192 self%NSCAN=mod(igdtmpl(16)/32,2)
193 self%nscan_field_pos = 3
194
195 iscale=igdtmpl(10)*igdtmpl(11)
196 IF(iscale==0) iscale=10**6
197
198 self%RLON0=float(igdtmpl(21))/float(iscale)
199 self%DLATS=float(igdtmpl(18))/float(iscale)
200 ! THE GRIB2 CONVENTION FOR "I" RESOLUTION IS TWICE WHAT THIS ROUTINE ASSUMES.
201 self%DLONS=float(igdtmpl(17))/float(iscale) * 0.5_kd
202
203 self%IROT=mod(igdtmpl(14)/8,2)
204
205 i_offset_odd=mod(igdtmpl(19)/8,2)
206 self%KSCAN=i_offset_odd
207 iscan=mod(igdtmpl(19)/128,2)
208
209 self%HI=(-1.)**iscan
210
211 rlat0=float(igdtmpl(20))/float(iscale)
212 rlat0=rlat0+90.0_kd
213
214 self%SLAT0=sin(rlat0/dpr)
215 self%CLAT0=cos(rlat0/dpr)
216
217 self%RLAT1=float(igdtmpl(12))/float(iscale)
218 self%RLON1=float(igdtmpl(13))/float(iscale)
219 end associate
220 end subroutine init_grib2
221
222
270 SUBROUTINE gdswzd_rot_equid_cylind_egrid(self,IOPT,NPTS,&
271 FILL,XPTS,YPTS,RLON,RLAT,NRET, &
272 CROT,SROT,XLON,XLAT,YLON,YLAT,AREA)
273 IMPLICIT NONE
274 !
275 class(ip_rot_equid_cylind_egrid), intent(in) :: self
276
277 INTEGER, INTENT(IN ) :: IOPT, NPTS
278 INTEGER, INTENT( OUT) :: NRET
279 !
280 REAL, INTENT(IN ) :: FILL
281 REAL, INTENT(INOUT) :: RLON(NPTS),RLAT(NPTS)
282 REAL, INTENT(INOUT) :: XPTS(NPTS),YPTS(NPTS)
283 REAL, OPTIONAL, INTENT( OUT) :: CROT(NPTS),SROT(NPTS)
284 REAL, OPTIONAL, INTENT( OUT) :: XLON(NPTS),XLAT(NPTS)
285 REAL, OPTIONAL, INTENT( OUT) :: YLON(NPTS),YLAT(NPTS),AREA(NPTS)
286 !
287 INTEGER :: IM, JM, IS1, N
288 INTEGER :: KSCAN
289 ! INTEGER :: I_OFFSET_ODD, I_OFFSET_EVEN
290 !
291 LOGICAL :: LROT, LMAP, LAREA
292 !
293 REAL(KIND=kd) :: rlat1, rlon1
294 REAL(KIND=kd) :: clonr
295 REAL(KIND=kd) :: rlatr, rlonr, sbd, wbd, hs, hi
296 REAL :: XMAX, XMIN, YMAX, YMIN, XPTF, YPTF
297 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
298 IF(PRESENT(crot)) crot=fill
299 IF(PRESENT(srot)) srot=fill
300 IF(PRESENT(xlon)) xlon=fill
301 IF(PRESENT(xlat)) xlat=fill
302 IF(PRESENT(ylon)) ylon=fill
303 IF(PRESENT(ylat)) ylat=fill
304 IF(PRESENT(area)) area=fill
305
306 rlon0=self%rlon0
307 irot=self%irot
308 im=self%im * 2 - 1
309 jm=self%jm
310 dlats=self%dlats
311 dlons=self%dlons
312 kscan=self%kscan
313 hi=self%hi
314 slat0=self%slat0
315 clat0=self%clat0
316 rlat1=self%rlat1
317 rlon1=self%rlon1
318
319 rerth = self%rerth
320
321 ! IS THE EARTH RADIUS DEFINED?
322 IF(rerth<0.)THEN
323 CALL rot_equid_cylind_egrid_error(iopt,fill,rlat,rlon,xpts,ypts,npts)
324 RETURN
325 ENDIF
326
327 sbd=rlat1
328 wbd=rlon1
329
330 IF (wbd > 180.0) wbd = wbd - 360.0
331 IF(kscan.EQ.0) THEN
332 is1=(jm+1)/2
333 ELSE
334 is1=jm/2
335 ENDIF
336
337 xmin=0
338 xmax=im+2
339 ymin=0
340 ymax=jm+1
341 nret=0
342
343 IF(PRESENT(crot).AND.PRESENT(srot))THEN
344 lrot=.true.
345 ELSE
346 lrot=.false.
347 ENDIF
348 IF(PRESENT(xlon).AND.PRESENT(xlat).AND.PRESENT(ylon).AND.PRESENT(ylat))THEN
349 lmap=.true.
350 ELSE
351 lmap=.false.
352 ENDIF
353 IF(PRESENT(area))THEN
354 larea=.true.
355 ELSE
356 larea=.false.
357 ENDIF
358
359 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
360 ! TRANSLATE GRID COORDINATES TO EARTH COORDINATES
361 IF(iopt.EQ.0.OR.iopt.EQ.1) THEN
362 DO n=1,npts
363 xptf=ypts(n)+(xpts(n)-is1)
364 yptf=ypts(n)-(xpts(n)-is1)+kscan
365 IF(xptf.GE.xmin.AND.xptf.LE.xmax.AND. &
366 yptf.GE.ymin.AND.yptf.LE.ymax) THEN
367 hs=hi*sign(1.,xptf-(im+1)/2)
368 select type(desc => self%descriptor)
369 type is(grib1_descriptor)
370 rlonr=(xptf-(im+1)/2)*dlons
371 rlatr=(yptf-(jm+1)/2)*dlats
372 type is(grib2_descriptor)
373 rlonr=(xptf-1.0_kd)*dlons + wbd
374 rlatr=(yptf-1.0_kd)*dlats + sbd
375 end select
376 clonr=cos(rlonr/dpr)
377 slatr=sin(rlatr/dpr)
378 clatr=cos(rlatr/dpr)
380 IF(slat.LE.-1) THEN
381 clat=0.
382 clon=cos(rlon0/dpr)
383 rlon(n)=0
384 rlat(n)=-90
385 ELSEIF(slat.GE.1) THEN
386 clat=0.
387 clon=cos(rlon0/dpr)
388 rlon(n)=0
389 rlat(n)=90
390 ELSE
391 clat=sqrt(1-slat**2)
393 clon=min(max(clon,-1._kd),1._kd)
394 rlon(n)=real(mod(rlon0+hs*dpr*acos(clon)+3600,360._kd))
395 rlat(n)=real(dpr*asin(slat))
396 ENDIF
397 nret=nret+1
398 IF(lrot) CALL rot_equid_cylind_egrid_vect_rot(rlon(n),crot(n),srot(n))
399 IF(lmap) CALL rot_equid_cylind_egrid_map_jacob(fill, rlon(n), &
400 xlon(n),xlat(n),ylon(n),ylat(n))
401 IF(larea) CALL rot_equid_cylind_egrid_grid_area(fill, area(n))
402 ELSE
403 rlon(n)=fill
404 rlat(n)=fill
405 ENDIF
406 ENDDO
407 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
408 ! TRANSLATE EARTH COORDINATES TO GRID COORDINATES
409 ELSEIF(iopt.EQ.-1) THEN
410 DO n=1,npts
411 IF(abs(rlon(n)).LE.360.AND.abs(rlat(n)).LE.90) THEN
412 hs=sign(1._kd,mod(rlon(n)-rlon0+180+3600,360._kd)-180)
413 clon=cos((rlon(n)-rlon0)/dpr)
414 slat=sin(rlat(n)/dpr)
415 clat=cos(rlat(n)/dpr)
417 IF(slatr.LE.-1) THEN
418 clatr=0.
419 rlonr=0
420 rlatr=-90
421 ELSEIF(slatr.GE.1) THEN
422 clatr=0.
423 rlonr=0
424 rlatr=90
425 ELSE
426 clatr=sqrt(1-slatr**2)
427 clonr=(clat0*clat*clon+slat0*slat)/clatr
428 clonr=min(max(clonr,-1._kd),1._kd)
429 rlonr=hs*dpr*acos(clonr)
430 rlatr=dpr*asin(slatr)
431 ENDIF
432 select type(desc => self%descriptor)
433 type is(grib1_descriptor)
434 xptf=real(((rlonr-wbd)/dlons)+1.0_kd)
435 yptf=real(((rlatr-sbd)/dlats)+1.0_kd)
436 type is(grib2_descriptor)
437 xptf=real((im+1)/2+rlonr/dlons)
438 yptf=real((jm+1)/2+rlatr/dlats)
439 end select
440
441 IF(xptf.GE.xmin.AND.xptf.LE.xmax.AND. &
442 yptf.GE.ymin.AND.yptf.LE.ymax) THEN
443 xpts(n)=is1+(xptf-(yptf-kscan))/2
444 ypts(n)=(xptf+(yptf-kscan))/2
445 nret=nret+1
446 IF(lrot) CALL rot_equid_cylind_egrid_vect_rot(rlon(n),crot(n),srot(n))
447 IF(lmap) CALL rot_equid_cylind_egrid_map_jacob(fill, rlon(n), &
448 xlon(n),xlat(n),ylon(n),ylat(n))
449 IF(larea) CALL rot_equid_cylind_egrid_grid_area(fill, area(n))
450 ELSE
451 xpts(n)=fill
452 ypts(n)=fill
453 ENDIF
454 ELSE
455 xpts(n)=fill
456 ypts(n)=fill
457 ENDIF
458 ENDDO
459 ENDIF
460 END SUBROUTINE gdswzd_rot_equid_cylind_egrid
461
485 SUBROUTINE rot_equid_cylind_egrid_error(IOPT,FILL,RLAT,RLON,XPTS,YPTS,NPTS)
486 IMPLICIT NONE
487 !
488 INTEGER, INTENT(IN ) :: IOPT, NPTS
489 !
490 REAL, INTENT(IN ) :: FILL
491 REAL, INTENT( OUT) :: RLAT(NPTS),RLON(NPTS)
492 REAL, INTENT( OUT) :: XPTS(NPTS),YPTS(NPTS)
493
494 IF(iopt>=0) THEN
495 rlon=fill
496 rlat=fill
497 ENDIF
498 IF(iopt<=0) THEN
499 xpts=fill
500 ypts=fill
501 ENDIF
502 END SUBROUTINE rot_equid_cylind_egrid_error
503
517 SUBROUTINE rot_equid_cylind_egrid_vect_rot(RLON, CROT, SROT)
518 IMPLICIT NONE
519
520 REAL , INTENT(IN ) :: RLON
521 REAL , INTENT( OUT) :: CROT, SROT
522
523 REAL(KIND=kd) :: slon
524
525 IF(irot.EQ.1) THEN
526 IF(clatr.LE.0) THEN
527 crot=real(-sign(1._kd,slatr*slat0))
528 srot=0.
529 ELSE
530 slon=sin((rlon-rlon0)/dpr)
531 crot=real((clat0*clat+slat0*slat*clon)/clatr)
532 srot=real(slat0*slon/clatr)
533 ENDIF
534 ELSE
535 crot=1.
536 srot=0.
537 ENDIF
538
540
552 SUBROUTINE rot_equid_cylind_egrid_map_jacob(FILL, RLON, &
553 XLON, XLAT, YLON, YLAT)
554 IMPLICIT NONE
555
556 REAL , INTENT(IN ) :: FILL, RLON
557 REAL , INTENT( OUT) :: XLON, XLAT, YLON, YLAT
558
559 REAL(KIND=kd) :: slon, term1, term2
560 REAL(KIND=kd) :: xlatf, xlonf, ylatf, ylonf
561
562 IF(clatr.LE.0._kd) THEN
563 xlon=fill
564 xlat=fill
565 ylon=fill
566 ylat=fill
567 ELSE
568 slon=sin((rlon-rlon0)/dpr)
569 term1=(clat0*clat+slat0*slat*clon)/clatr
570 term2=slat0*slon/clatr
571 xlonf=term1*clat/(dlons*clatr)
572 xlatf=-term2/(dlons*clatr)
573 ylonf=term2*clat/dlats
574 ylatf=term1/dlats
575 xlon=real(xlonf-ylonf)
576 xlat=real(xlatf-ylatf)
577 ylon=real(xlonf+ylonf)
578 ylat=real(xlatf+ylatf)
579 ENDIF
580
582
590 SUBROUTINE rot_equid_cylind_egrid_grid_area(FILL, AREA)
591 IMPLICIT NONE
592
593 REAL, INTENT(IN ) :: FILL
594 REAL, INTENT( OUT) :: AREA
595
596 IF(clatr.LE.0._kd) THEN
597 area=fill
598 ELSE
599 area=real(rerth**2*clatr*dlats*dlons)*2/dpr**2
600 ENDIF
601
603
605
606
void gdswzd(int igdtnum, int *igdtmpl, int igdtlen, int iopt, int npts, float fill, float *xpts, float *ypts, float *rlon, float *rlat, int *nret, float *crot, float *srot, float *xlon, float *xlat, float *ylon, float *ylat, float *area)
gdswzd() interface for C for _4 build of library.
Determine earth radius and shape.
Module containing common constants.
real, parameter pi
PI.
real, parameter dpr
Radians to degrees.
Users derived type grid descriptor objects to abstract away the raw GRIB1 and GRIB2 grid definitions.
Abstract ip_grid type.
Rotated equidistant cylindrical GRIB decoder and grid coordinate transformations for Arakawa grid E.
real(kind=kd) dlats
Local copy of dlats.
real(kind=kd) rlon0
Local copy of rlon0.
real(kind=kd) slatr
Sine of the rotated latitude.
integer, parameter kd
Kind of reals.
real(kind=kd) clon
Cosine of the difference between rlon and rlon0.
real(kind=kd) slat0
Local copy of slat0.
real(kind=kd) clat0
Local copy of clat0.
subroutine rot_equid_cylind_egrid_grid_area(fill, area)
Computes the grid box area for a rotated equidistant cylindrical grid.
subroutine gdswzd_rot_equid_cylind_egrid(self, iopt, npts, fill, xpts, ypts, rlon, rlat, nret, crot, srot, xlon, xlat, ylon, ylat, area)
Calculates Earth coordinates (iopt = 1) or grid coorindates (iopt = -1) for rotated equidistant cylin...
subroutine init_grib1(self, g1_desc)
Initializes a rotated equidistant cylindrical grid given a grib1_descriptor object.
real(kind=kd) clat
Cosine of the latitude.
real(kind=kd) clatr
Cosine of the rotated latitude.
subroutine rot_equid_cylind_egrid_error(iopt, fill, rlat, rlon, xpts, ypts, npts)
Error handler.
subroutine rot_equid_cylind_egrid_vect_rot(rlon, crot, srot)
Computes the vector rotation sines and cosines for a rotated equidistant cylindrical grid.
real(kind=kd) slat
Sine of the latitude.
real(kind=kd) rerth
Radius of the Earth.
subroutine rot_equid_cylind_egrid_map_jacob(fill, rlon, xlon, xlat, ylon, ylat)
Computes the map jacobians for a rotated equidistant cylindrical grid.
real(kind=kd) dlons
Local copy of dlons.
subroutine init_grib2(self, g2_desc)
Initializes a rotated equidistant cylindrical grid given a grib2_descriptor object.
Descriptor representing a grib1 grib descriptor section (GDS) with an integer array.
Abstract grid that holds fields and methods common to all grids.