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