NCEPLIBS-ip  4.2.0
ip_gaussian_grid_mod.F90
Go to the documentation of this file.
1 
5 
16  use ip_grid_mod
18  use constants_mod
19  implicit none
20 
21  private
22  public :: ip_gaussian_grid
23 
24  type, extends(ip_grid) :: ip_gaussian_grid
25  integer :: jh
26  real :: dlon
27  real :: rlat1
28  real :: rlon1
29  real :: rlon2
30  real :: hi
31  integer :: jg
32  integer :: jscan
33  contains
35  procedure :: init_grib1
37  procedure :: init_grib2
40  procedure :: gdswzd => gdswzd_gaussian
41  end type ip_gaussian_grid
42 
43  INTEGER :: j1
44  INTEGER :: jh
45  REAL, ALLOCATABLE :: blat(:)
46  REAL :: dlon
47  REAL :: rerth
48  REAL, ALLOCATABLE :: ylat_row(:)
49 
50 contains
51 
59  subroutine init_grib1(self, g1_desc)
60  class(ip_gaussian_grid), intent(inout) :: self
61  type(grib1_descriptor), intent(in) :: g1_desc
62 
63  integer :: iscan, jg
64 
65  associate(kgds => g1_desc%gds)
66  self%rerth = 6.3712e6
67  self%eccen_squared = 0.0
68 
69  self%IM=kgds(2)
70  self%JM=kgds(3)
71  self%RLAT1=kgds(4)*1.e-3
72  self%RLON1=kgds(5)*1.e-3
73  self%RLON2=kgds(8)*1.e-3
74  self%JG=kgds(10)*2
75  iscan=mod(kgds(11)/128,2)
76  self%JSCAN=mod(kgds(11)/64,2)
77  self%HI=(-1.)**iscan
78  self%JH=(-1)**self%JSCAN
79  self%DLON=self%HI*(mod(self%HI*(self%RLON2-self%RLON1)-1+3600,360.)+1)/(self%IM-1)
80 
81  self%iwrap = 0
82  self%jwrap1 = 0
83  self%jwrap2 = 0
84  self%nscan = mod(kgds(11) / 32, 2)
85  self%nscan_field_pos = self%nscan
86  self%kscan = 0
87 
88  self%iwrap=nint(360 / abs(self%dlon))
89  if(self%im < self%iwrap) self%iwrap = 0
90 
91  if(self%iwrap > 0 .and. mod(self%iwrap, 2) == 0) then
92  jg=kgds(10)*2
93  if(self%jm == self%jg) then
94  self%jwrap1 = 1
95  self%jwrap2 = 2 * self%jm + 1
96  endif
97  endif
98 
99  end associate
100  end subroutine init_grib1
101 
108  subroutine init_grib2(self, g2_desc)
109  class(ip_gaussian_grid), intent(inout) :: self
110  type(grib2_descriptor), intent(in) :: g2_desc
111 
112  integer :: iscale, iscan, jg
113 
114  associate(igdtmpl => g2_desc%gdt_tmpl, igdtlen => g2_desc%gdt_len)
115  call earth_radius(igdtmpl, igdtlen, self%rerth, self%eccen_squared)
116 
117  self%IM=igdtmpl(8)
118  self%JM=igdtmpl(9)
119  iscale=igdtmpl(10)*igdtmpl(11)
120  IF(iscale==0) iscale=10**6
121  self%RLAT1=float(igdtmpl(12))/float(iscale)
122  self%RLON1=float(igdtmpl(13))/float(iscale)
123  self%RLON2=float(igdtmpl(16))/float(iscale)
124  self%JG=igdtmpl(18)*2
125  iscan=mod(igdtmpl(19)/128,2)
126  self%JSCAN=mod(igdtmpl(19)/64,2)
127  self%HI=(-1.)**iscan
128  self%JH=(-1)**self%JSCAN
129  self%DLON=self%HI*(mod(self%HI*(self%RLON2-self%RLON1)-1+3600,360.)+1)/(self%IM-1)
130 
131 
132  self%iwrap = nint(360 / abs(self%dlon))
133  if(self%im < self%iwrap) self%iwrap = 0
134  self%jwrap1 = 0
135  self%jwrap2 = 0
136  if(self%iwrap > 0 .and. mod(self%iwrap, 2) == 0) then
137  jg = igdtmpl(18) * 2
138  if(self%jm == jg) then
139  self%jwrap1=1
140  self%jwrap2 = 2 * self%jm + 1
141  endif
142  endif
143  self%nscan = mod(igdtmpl(19) / 32, 2)
144  self%nscan_field_pos = self%nscan
145  self%kscan = 0
146  end associate
147 
148  end subroutine init_grib2
149 
194  SUBROUTINE gdswzd_gaussian(self,IOPT,NPTS,FILL, &
195  XPTS,YPTS,RLON,RLAT,NRET, &
196  CROT,SROT,XLON,XLAT,YLON,YLAT,AREA)
197  IMPLICIT NONE
198  !
199  class(ip_gaussian_grid), intent(in) :: self
200  INTEGER, INTENT(IN ) :: IOPT, NPTS
201  INTEGER, INTENT( OUT) :: NRET
202  !
203  REAL, INTENT(IN ) :: FILL
204  REAL, INTENT(INOUT) :: RLON(NPTS),RLAT(NPTS)
205  REAL, INTENT(INOUT) :: XPTS(NPTS),YPTS(NPTS)
206  REAL, OPTIONAL, INTENT( OUT) :: CROT(NPTS),SROT(NPTS)
207  REAL, OPTIONAL, INTENT( OUT) :: XLON(NPTS),XLAT(NPTS)
208  REAL, OPTIONAL, INTENT( OUT) :: YLON(NPTS),YLAT(NPTS),AREA(NPTS)
209  !
210  INTEGER :: JSCAN, IM, JM
211  INTEGER :: J, JA, JG
212  INTEGER :: N
213  !
214  LOGICAL :: LROT, LMAP, LAREA
215  !
216  REAL, ALLOCATABLE :: ALAT(:), ALAT_JSCAN(:)
217  REAL, ALLOCATABLE :: ALAT_TEMP(:),BLAT_TEMP(:)
218  REAL :: HI, RLATA, RLATB, RLAT1, RLON1, RLON2
219  REAL :: XMAX, XMIN, YMAX, YMIN, YPTSA, YPTSB
220  REAL :: WB
221 
222  IF(PRESENT(crot)) crot=fill
223  IF(PRESENT(srot)) srot=fill
224  IF(PRESENT(xlon)) xlon=fill
225  IF(PRESENT(xlat)) xlat=fill
226  IF(PRESENT(ylon)) ylon=fill
227  IF(PRESENT(ylat)) ylat=fill
228  IF(PRESENT(area)) area=fill
229 
230  IF(PRESENT(crot).AND.PRESENT(srot))THEN
231  lrot=.true.
232  ELSE
233  lrot=.false.
234  ENDIF
235  IF(PRESENT(xlon).AND.PRESENT(xlat).AND.PRESENT(ylon).AND.PRESENT(ylat))THEN
236  lmap=.true.
237  ELSE
238  lmap=.false.
239  ENDIF
240  IF(PRESENT(area))THEN
241  larea=.true.
242  ELSE
243  larea=.false.
244  ENDIF
245 
246  im=self%im
247  jm=self%jm
248 
249  rlat1=self%rlat1
250  rlon1=self%rlon1
251  rlon2=self%rlon2
252 
253  jg=self%jg
254  jscan=self%jscan
255  hi=self%hi
256 
257  jh=self%jh
258  dlon=self%dlon
259  rerth = self%rerth
260 
261  ALLOCATE(alat_temp(jg))
262  ALLOCATE(blat_temp(jg))
263  CALL splat(4,jg,alat_temp,blat_temp)
264  ALLOCATE(alat(0:jg+1))
265  ALLOCATE(blat(0:jg+1))
266  !$OMP PARALLEL DO PRIVATE(JA) SCHEDULE(STATIC)
267  DO ja=1,jg
268  alat(ja)=real(dpr*asin(alat_temp(ja)))
269  blat(ja)=blat_temp(ja)
270  ENDDO
271  !$OMP END PARALLEL DO
272  DEALLOCATE(alat_temp,blat_temp)
273  alat(0)=180.-alat(1)
274  alat(jg+1)=-alat(0)
275  blat(0)=-blat(1)
276  blat(jg+1)=blat(0)
277  j1=1
278  DO WHILE(j1.LT.jg.AND.rlat1.LT.(alat(j1)+alat(j1+1))/2)
279  j1=j1+1
280  ENDDO
281  IF(lmap)THEN
282  ALLOCATE(alat_jscan(jg))
283  DO ja=1,jg
284  alat_jscan(j1+jh*(ja-1))=alat(ja)
285  ENDDO
286  ALLOCATE(ylat_row(0:jg+1))
287  DO ja=2,(jg-1)
288  ylat_row(ja)=2.0/(alat_jscan(ja+1)-alat_jscan(ja-1))
289  ENDDO
290  ylat_row(1)=1.0/(alat_jscan(2)-alat_jscan(1))
291  ylat_row(0)=ylat_row(1)
292  ylat_row(jg)=1.0/(alat_jscan(jg)-alat_jscan(jg-1))
293  ylat_row(jg+1)=ylat_row(jg)
294  DEALLOCATE(alat_jscan)
295  ENDIF
296  xmin=0
297  xmax=im+1
298  IF(im.EQ.nint(360/abs(dlon))) xmax=im+2
299  ymin=0.5
300  ymax=jm+0.5
301  nret=0
302 
303  ! TRANSLATE GRID COORDINATES TO EARTH COORDINATES
304  IF(iopt.EQ.0.OR.iopt.EQ.1) THEN
305  !$OMP PARALLEL DO PRIVATE(N,J,WB,RLATA,RLATB) REDUCTION(+:NRET) SCHEDULE(STATIC)
306  DO n=1,npts
307  IF(xpts(n).GE.xmin.AND.xpts(n).LE.xmax.AND. &
308  ypts(n).GE.ymin.AND.ypts(n).LE.ymax) THEN
309  rlon(n)=mod(rlon1+dlon*(xpts(n)-1)+3600,360.)
310  j=int(ypts(n))
311  wb=ypts(n)-j
312  rlata=alat(j1+jh*(j-1))
313  rlatb=alat(j1+jh*j)
314  rlat(n)=rlata+wb*(rlatb-rlata)
315  nret=nret+1
316  IF(lrot) CALL gaussian_vect_rot(crot(n),srot(n))
317  IF(lmap) CALL gaussian_map_jacob(ypts(n),&
318  xlon(n),xlat(n),ylon(n),ylat(n))
319  IF(larea) CALL gaussian_grid_area(ypts(n),area(n))
320  ELSE
321  rlon(n)=fill
322  rlat(n)=fill
323  ENDIF
324  ENDDO
325  !$OMP END PARALLEL DO
326 
327  ! TRANSLATE EARTH COORDINATES TO GRID COORDINATES
328  ELSEIF(iopt.EQ.-1) THEN
329  !$OMP PARALLEL DO PRIVATE(N,JA,YPTSA, YPTSB, WB) REDUCTION(+:NRET) SCHEDULE(STATIC)
330  DO n=1,npts
331  xpts(n)=fill
332  ypts(n)=fill
333  IF(abs(rlon(n)).LE.360.AND.abs(rlat(n)).LE.90) THEN
334  xpts(n)=1+hi*mod(hi*(rlon(n)-rlon1)+3600,360.)/dlon
335  ja=min(int((jg+1)/180.*(90-rlat(n))),jg)
336  IF(rlat(n).GT.alat(ja)) ja=max(ja-2,0)
337  IF(rlat(n).LT.alat(ja+1)) ja=min(ja+2,jg)
338  IF(rlat(n).GT.alat(ja)) ja=ja-1
339  IF(rlat(n).LT.alat(ja+1)) ja=ja+1
340  yptsa=1+jh*(ja-j1)
341  yptsb=1+jh*(ja+1-j1)
342  wb=(alat(ja)-rlat(n))/(alat(ja)-alat(ja+1))
343  ypts(n)=yptsa+wb*(yptsb-yptsa)
344  IF(xpts(n).GE.xmin.AND.xpts(n).LE.xmax.AND. &
345  ypts(n).GE.ymin.AND.ypts(n).LE.ymax) THEN
346  nret=nret+1
347  IF(lrot) CALL gaussian_vect_rot(crot(n),srot(n))
348  IF(lmap) CALL gaussian_map_jacob(ypts(n), &
349  xlon(n),xlat(n),ylon(n),ylat(n))
350  IF(larea) CALL gaussian_grid_area(ypts(n),area(n))
351  ELSE
352  xpts(n)=fill
353  ypts(n)=fill
354  ENDIF
355  ENDIF
356  ENDDO
357  !$OMP END PARALLEL DO
358  ENDIF
359  DEALLOCATE(alat, blat)
360  IF (ALLOCATED(ylat_row)) DEALLOCATE(ylat_row)
361 
362  END SUBROUTINE gdswzd_gaussian
363 
376  SUBROUTINE gaussian_vect_rot(CROT,SROT)
377  IMPLICIT NONE
378 
379  REAL, INTENT( OUT) :: CROT, SROT
380 
381  crot=1.0
382  srot=0.0
383 
384  END SUBROUTINE gaussian_vect_rot
385 
396  SUBROUTINE gaussian_map_jacob(YPTS, XLON, XLAT, YLON, YLAT)
397  IMPLICIT NONE
398 
399  REAL, INTENT(IN ) :: YPTS
400  REAL, INTENT( OUT) :: XLON, XLAT, YLON, YLAT
401 
402  xlon=1/dlon
403  xlat=0.
404  ylon=0.
405  ylat=ylat_row(nint(ypts))
406 
407  END SUBROUTINE gaussian_map_jacob
408 
416  SUBROUTINE gaussian_grid_area(YPTS,AREA)
417  IMPLICIT NONE
418 
419  REAL, INTENT(IN ) :: YPTS
420  REAL, INTENT( OUT) :: AREA
421 
422  INTEGER :: J
423 
424  REAL :: WB, WLAT, WLATA, WLATB
425 
426  j = int(ypts)
427  wb=ypts-j
428  wlata=blat(j1+jh*(j-1))
429  wlatb=blat(j1+jh*j)
430  wlat=wlata+wb*(wlatb-wlata)
431  area=real(rerth**2*wlat*dlon/dpr)
432 
433  END SUBROUTINE gaussian_grid_area
434 end module ip_gaussian_grid_mod
435 
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.
Determine earth radius and shape.
Gaussian grid coordinate transformations.
real, dimension(:), allocatable ylat_row
dy/dlat for each row in 1/degrees.
integer jh
Scan mode flag in 'j' direction.
subroutine gdswzd_gaussian(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 Gaussian grids.
real rerth
Radius of the earth.
real dlon
"i"-direction increment.
subroutine init_grib1(self, g1_desc)
Initializes a gaussian grid given a grib1_descriptor object.
subroutine gaussian_grid_area(YPTS, AREA)
Computes the grid box area for a gaussian cylindrical grid.
subroutine gaussian_vect_rot(CROT, SROT)
Computes the vector rotation sines and cosines for a gaussian cylindrical grid.
subroutine gaussian_map_jacob(YPTS, XLON, XLAT, YLON, YLAT)
Computes the map jacobians for a gaussian cylindrical grid.
subroutine init_grib2(self, g2_desc)
Initializes a gaussian grid given a grib2_descriptor object.
real, dimension(:), allocatable blat
Gaussian latitude for each parallel.
integer j1
'j' index of first grid point within the global array of latitudes.
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
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