NCEPLIBS-ip 5.3.0
All Data Structures Namespaces Files Functions Variables Pages
ip_grid_mod.F90
Go to the documentation of this file.
1!> @file
2!! @brief Abstract ip_grid type.
3!!
4!! @author Kyle Gerheiser @date July 2021
5
6!> Abstract ip_grid type.
7!!
8!! @author Kyle Gerheiser
9!! @date July 2021
12 use iso_c_binding, only : c_bool
13 implicit none
14
15 integer, public, parameter :: equid_cylind_grid_id_grib1 = 0 !< Integer grid number for equidistant cylindrical grid in grib1
16 integer, public, parameter :: mercator_grid_id_grib1 = 1 !< Integer grid number for Mercator grid in grib1
17 integer, public, parameter :: lambert_conf_grid_id_grib1 = 3 !< Integer grid number for Lambert Conformal grid in grib1
18 integer, public, parameter :: gaussian_grid_id_grib1 = 4 !< Integer grid number for Gaussian grid in grib1
19 integer, public, parameter :: polar_stereo_grid_id_grib1 = 5 !< Integer grid number for polar stereo grid in grib1
20 integer, public, parameter :: rot_equid_cylind_e_grid_id_grib1 = 203 !< Integer grid number for rotated equidistant cylindrical E-stagger grid
21 integer, public, parameter :: rot_equid_cylind_b_grid_id_grib1 = 205 !< Integer grid number for rotated equidistant cylindrical B-stagger grid
22
23 integer, public, parameter :: equid_cylind_grid_id_grib2 = 0 !< Integer grid number for equidistant cylindrical grid in grib2
24 integer, public, parameter :: rot_equid_cylind_grid_id_grib2 = 1 !< Integer grid number for rotated equidistant cylindrical grid in grib2
25 integer, public, parameter :: mercator_grid_id_grib2 = 10 !< Integer grid number for Mercator grid in grib2
26 integer, public, parameter :: polar_stereo_grid_id_grib2 = 20 !< Integer grid number for polar stereo grid in grib2
27 integer, public, parameter :: lambert_conf_grid_id_grib2 = 30 !< Integer grid number for Lambert conformal grid in grib2
28 integer, public, parameter :: gaussian_grid_id_grib2 = 40 !< Integer grid number for Gaussian grid in grib2
29 integer, public, parameter :: rot_equid_cylind_e_grid_id_grib2 = 32768 !< Integer grid number for rotated equidistant cylindrical E-stagger grid (grib2)
30 integer, public, parameter :: rot_equid_cylind_b_grid_id_grib2 = 32769 !< Integer grid number for rotated equidistant cylindrical B-stagger grid (grib2)
31
32 logical(c_bool), public, save, bind(c) :: ncep_post_arakawa=.false. !< Use ncep_post/wgrib2-compatible version of init_grib2() for non-E Arakawa grids (enable with use_ncep_post_arakawa())
33
34 private
35 public :: ip_grid
36 public :: gdswzd_interface
37 public :: operator(==)
38 public :: use_ncep_post_arakawa
40
41 !> Abstract grid that holds fields and methods common to all grids.
42 !! ip_grid is meant to be subclassed when implementing a new grid.
43 !!
44 !! There are three methods that must be implemented:
45 !! - init_grib1()
46 !! - init_grib2()
47 !! - gdswzd()
48 !!
49 !! The init methods are responsible for setting up the grid
50 !! using GRIB1/GRIB2 descriptors.
51 !!
52 !! gdswzd() performs transformations to and from Earth coordinates
53 !! and grid coordinates.
54 !!
55 !! A good reference for all the map projection equations used by
56 !! NCEPLIBS-ip can be found here: https://doi.org/10.3133/pp1395.
57 !!
58 !! @author Kyle Gerheiser @date July 2021
59 type, abstract :: ip_grid
60 class(ip_grid_descriptor), allocatable :: descriptor !< Descriptor.
61
62 integer :: im !< Number of x points
63 integer :: jm !< Number of y points
64 integer :: nm !< Total number of points
65
66 !> @param Scanning mode.
67 !! - 0 if x first then y;
68 !! - 1 if y first then x;
69 !! - 3 if staggered diagonal like projection 203.
70 integer :: nscan
71 integer :: kscan !< Mass/wind flag for staggered diagonal (0 if mass; 1 if wind).
72
73 integer :: nscan_field_pos !< nscan for field_pos routine. Can be different than nscan due to differences in grib/grib2.
74
75 integer :: iwrap !< x wraparound increment (0 if no wraparound).
76 integer :: jwrap1 !< y wraparound lower pivot point (0 if no wraparound).
77 integer :: jwrap2 !< y wraparound upper pivot point (0 if no wraparound).
78 real :: rerth !< Radius of the Earth.
79 real :: eccen_squared !< Eccentricity of the Earth squared (e^2).
80 contains
81 !> @cond skip
82 !> Initializer for grib1 input descriptor.
83 procedure(init_grib1_interface), deferred :: init_grib1
84 !> Initializer for grib2 input descriptor.
85 procedure(init_grib2_interface), deferred :: init_grib2
86 !> Coordinate transformations for the grid.
87 procedure(gdswzd_interface), deferred :: gdswzd
88 !> @endcond
89 !> Field position for a given grid point. @return Integer
90 !> position in grib field to locate grid point.
91 !> @copydoc ip_grid_mod::field_pos
92 procedure :: field_pos
93 !> Init subprogram. @return N/A
94 generic :: init => init_grib1, init_grib2
95 end type ip_grid
96
97 abstract interface
98
99 !> @fn ip_grid_mod::gdswzd_interface::gdswzd_interface(self,
100 !> iopt, npts, fill, xpts, ypts, rlon, rlat, nret, crot, srot,
101 !> xlon, xlat, ylon, ylat, area)
102 !> Interface to gdswzd().
103 !>
104 !> @param[in] self ip_grid_mod object.
105 !> @param[in] iopt option flag
106 !> - 1 to compute earth coords of selected grid coords
107 !> - -1 to compute grid coords of selected earth coords
108 !> @param[in] npts maximum number of coordinates
109 !> @param[in] fill fill value to set invalid output data (must be
110 !> impossible value; suggested value: -9999.)
111 !> @param[inout] xpts (npts) grid x point coordinates if iopt>0
112 !> @param[inout] ypts (npts) grid y point coordinates if iopt>0
113 !> @param[inout] rlon (npts) earth longitudes in degrees e if iopt<0
114 !> (acceptable range: -360. to 360.)
115 !> @param[inout] rlat (npts) earth latitudes in degrees n if iopt<0
116 !> (acceptable range: -90. to 90.)
117 !> @param[out] nret number of valid points computed
118 !> @param[out] crot optional (npts) clockwise vector rotation cosines
119 !> @param[out] srot optional (npts) clockwise vector rotation sines
120 !> (ugrid=crot*uearth-srot*vearth; vgrid=srot*uearth+crot*vearth)
121 !> @param[out] xlon optional (npts) dx/dlon in 1/degrees
122 !> @param[out] xlat optional (npts) dx/dlat in 1/degrees
123 !> @param[out] ylon optional (npts) dy/dlon in 1/degrees
124 !> @param[out] ylat optional (npts) dy/dlat in 1/degrees
125 !> @param[out] area optional (npts) area weights in m**2
126 !> (proportional to the square of the map factor)
127 !>
128 !> @author Kyle Gerheiser @date July 2021
129 subroutine gdswzd_interface(self, iopt, npts, fill, xpts, ypts, rlon, rlat, nret, crot, srot, &
130 xlon, xlat, ylon, ylat, area)
131 import
132 class(ip_grid), intent(in) :: self
133 INTEGER, INTENT(IN ) :: IOPT, NPTS
134 INTEGER, INTENT( OUT) :: NRET
135 !
136 REAL, INTENT(IN ) :: FILL
137 REAL, INTENT(INOUT) :: RLON(NPTS),RLAT(NPTS)
138 REAL, INTENT(INOUT) :: XPTS(NPTS),YPTS(NPTS)
139 REAL, OPTIONAL, INTENT( OUT) :: CROT(NPTS),SROT(NPTS)
140 REAL, OPTIONAL, INTENT( OUT) :: XLON(NPTS),XLAT(NPTS)
141 REAL, OPTIONAL, INTENT( OUT) :: YLON(NPTS),YLAT(NPTS),AREA(NPTS)
142 end subroutine gdswzd_interface
143
144 !> @fn ip_grid_mod::init_grib1_interface::init_grib1_interface(self, g1_desc)
145 !> Init GRIB1 interface.
146 !>
147 !> @param[inout] self ip_grid_mod object.
148 !> @param[in] g1_desc GRIB1 descriptor.
149 !>
150 !> @author Kyle Gerheiser
151 !> @date July 2021
152 subroutine init_grib1_interface(self, g1_desc)
153 import
154 class(ip_grid), intent(inout) :: self
155 type(grib1_descriptor), intent(in) :: g1_desc
156 end subroutine init_grib1_interface
157
158 !> @fn ip_grid_mod::init_grib2_interface::init_grib2_interface(self, g2_desc)
159 !> Init GRIB2 interface.
160 !>
161 !> @param[inout] self ip_grid_mod object.
162 !> @param[in] g2_desc GRIB2 descriptor.
163 !>
164 !> @author Kyle Gerheiser
165 !> @date July 2021
166 subroutine init_grib2_interface(self, g2_desc)
167 import
168 class(ip_grid), intent(inout) :: self
169 type(grib2_descriptor), intent(in) :: g2_desc
170 end subroutine init_grib2_interface
171
172 end interface
173
174 !> Check equality.
175 !> @author Kyle Gerheiser @date July 2021
176 interface operator (==)
177 module procedure is_same_grid
178 end interface operator (==)
179
180
181contains
182
183 !> Enables ncep_post/wgrib2-compatible non-E Arakawa grib2 grids
184 !> by setting 'ncep_post_arakawa=.true.'.
185 !> This subroutine should be called prior to init_grib2().
186 !>
187 !> @author Alex Richert
188 !> @date May 2024
189 subroutine use_ncep_post_arakawa() bind(c)
190 ncep_post_arakawa = .true.
191 end subroutine use_ncep_post_arakawa
192
193 !> Disables ncep_post/wgrib2-compatible non-E Arakawa grib2 grids
194 !> by setting 'ncep_post_arakawa=.false.'.
195 !> This subroutine should be called prior to init_grib2().
196 !>
197 !> @author Alex Richert
198 !> @date May 2024
199 subroutine unuse_ncep_post_arakawa() bind(c)
200 ncep_post_arakawa = .false.
201 end subroutine unuse_ncep_post_arakawa
202
203 !> Compares two grids.
204 !>
205 !> @param[in] grid1 An ip_grid
206 !> @param[in] grid2 Another ip_grid
207 !>
208 !> @return True if the grids are the same, false if not.
209 !>
210 !> @author Kyle Gerheiser
211 !> @date July 2021
212 logical function is_same_grid(grid1, grid2)
213 class(ip_grid), intent(in) :: grid1, grid2
214 is_same_grid = grid1%descriptor == grid2%descriptor
215 end function is_same_grid
216
217 !> Returns the field position for a given grid point.
218 !>
219 !> @param[in] self
220 !> @param[in] i
221 !> @param[in] j
222 !>
223 !> @return Integer position in grib field to locate grid point.
224 !>
225 !> @author Mark Iredell, George Gayno, Kyle Gerheiser
226 !> @date April 1996
227 function field_pos(self, i, j)
228 class(ip_grid), intent(in) :: self
229 integer, intent(in) :: i, j
230 integer :: field_pos
231
232 integer :: ii, jj, im, jm
233 integer :: iif, jjf, is1, iwrap
234 integer :: jwrap1, jwrap2, kscan, nscan
235
236 ! extract from navigation parameter array
237 im=self%im
238 jm=self%jm
239 iwrap=self%iwrap
240 jwrap1=self%jwrap1
241 jwrap2=self%jwrap2
242 nscan=self%nscan_field_pos
243 kscan=self%kscan
244
245 ! compute wraparounds in x and y if necessary and possible
246 ii=i
247 jj=j
248 if(iwrap.gt.0) then
249 ii=mod(i-1+iwrap,iwrap)+1
250 if(j.lt.1.and.jwrap1.gt.0) then
251 jj=jwrap1-j
252 ii=mod(ii-1+iwrap/2,iwrap)+1
253 elseif(j.gt.jm.and.jwrap2.gt.0) then
254 jj=jwrap2-j
255 ii=mod(ii-1+iwrap/2,iwrap)+1
256 endif
257 endif
258
259 ! compute position for the appropriate scanning mode
260 field_pos=0
261 if(nscan.eq.0) then
262 if(ii.ge.1.and.ii.le.im.and.jj.ge.1.and.jj.le.jm) field_pos=ii+(jj-1)*im
263 elseif(nscan.eq.1) then
264 if(ii.ge.1.and.ii.le.im.and.jj.ge.1.and.jj.le.jm) field_pos=jj+(ii-1)*jm
265 elseif(nscan.eq.2) then
266 is1=(jm+1-kscan)/2
267 iif=jj+(ii-is1)
268 jjf=jj-(ii-is1)+kscan
269 if(iif.ge.1.and.iif.le.2*im-1.and.jjf.ge.1.and.jjf.le.jm) &
270 field_pos=(iif+(jjf-1)*(2*im-1)+1-kscan)/2
271 elseif(nscan.eq.3) then
272 is1=(jm+1-kscan)/2
273 iif=jj+(ii-is1)
274 jjf=jj-(ii-is1)+kscan
275 if(iif.ge.1.and.iif.le.2*im-1.and.jjf.ge.1.and.jjf.le.jm) field_pos=(iif+1)/2+(jjf-1)*im
276 endif
277 end function field_pos
278
279
280end module ip_grid_mod
281
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.
Users derived type grid descriptor objects to abstract away the raw GRIB1 and GRIB2 grid definitions.
logical function is_same_grid(grid1, grid2)
Test whether two grid descriptors are the same.
Abstract ip_grid type.
subroutine, public use_ncep_post_arakawa()
Enables ncep_post/wgrib2-compatible non-E Arakawa grib2 grids by setting 'ncep_post_arakawa=....
integer, parameter, public rot_equid_cylind_e_grid_id_grib2
Integer grid number for rotated equidistant cylindrical E-stagger grid (grib2)
integer, parameter, public lambert_conf_grid_id_grib2
Integer grid number for Lambert conformal grid in grib2.
integer, parameter, public gaussian_grid_id_grib2
Integer grid number for Gaussian grid in grib2.
integer, parameter, public equid_cylind_grid_id_grib2
Integer grid number for equidistant cylindrical grid in grib2.
integer, parameter, public gaussian_grid_id_grib1
Integer grid number for Gaussian grid in grib1.
integer, parameter, public rot_equid_cylind_e_grid_id_grib1
Integer grid number for rotated equidistant cylindrical E-stagger grid.
integer, parameter, public polar_stereo_grid_id_grib2
Integer grid number for polar stereo grid in grib2.
integer function field_pos(self, i, j)
Returns the field position for a given grid point.
logical(c_bool), save, bind(C), public ncep_post_arakawa
Use ncep_post/wgrib2-compatible version of init_grib2() for non-E Arakawa grids (enable with use_ncep...
integer, parameter, public lambert_conf_grid_id_grib1
Integer grid number for Lambert Conformal grid in grib1.
integer, parameter, public mercator_grid_id_grib1
Integer grid number for Mercator grid in grib1.
subroutine, public unuse_ncep_post_arakawa()
Disables ncep_post/wgrib2-compatible non-E Arakawa grib2 grids by setting 'ncep_post_arakawa=....
integer, parameter, public equid_cylind_grid_id_grib1
Integer grid number for equidistant cylindrical grid in grib1.
integer, parameter, public rot_equid_cylind_b_grid_id_grib1
Integer grid number for rotated equidistant cylindrical B-stagger grid.
integer, parameter, public rot_equid_cylind_b_grid_id_grib2
Integer grid number for rotated equidistant cylindrical B-stagger grid (grib2)
integer, parameter, public rot_equid_cylind_grid_id_grib2
Integer grid number for rotated equidistant cylindrical grid in grib2.
integer, parameter, public mercator_grid_id_grib2
Integer grid number for Mercator grid in grib2.
integer, parameter, public polar_stereo_grid_id_grib1
Integer grid number for polar stereo grid in grib1.
Descriptor representing a grib1 grib descriptor section (GDS) with an integer array.
Grib-2 descriptor containing a grib2 GDT represented by an integer array.
Abstract descriptor object which represents a grib1 or grib2 descriptor.
Abstract grid that holds fields and methods common to all grids.