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