IODA Bundle
goes_latlon.py
Go to the documentation of this file.
1 #
2 # goes_latlon.py
3 #
4 # This class generates a single IODAv2 data file with the following groups, variables, attributes and
5 # dimensions. This program is designed to be executed from the GoesConverter class is the event that the
6 # nadir for GOES-16 or GOES-17 has changed. Once created, the GoesConverter class will consume this file for each
7 # conversion. The argument source_file_path must be a GOES-16 or GOES-17 file with 2km resolution. Calculations within
8 # this program utilize section 5.1.2.8.1 of the GOES R SERIES PRODUCT DEFINITION AND USERS' GUIDE Dec 17, 2019
9 # REVISION 2.2 416-R-PUG-L1B-0347 Vol 3
10 #
11 # /GROUP/VARIABLE -> ATTRIBUTE
12 #
13 # /MetaData/elevation_angle
14 # /MetaData/scan_angle
15 # /MetaData/latitude
16 # /MetaData/latitude -> lat_nadir
17 # /MetaData/longitude
18 # /MetaData/longitude -> lon_nadir
19 # /nlocs
20 #
21 from netCDF4 import Dataset
22 from numpy import ma
23 import numpy as np
24 
25 
26 class GoesLatLon:
27 
28  def __init__(self, source_file_path, latlon_file_path):
29  """
30  Constructor
31  source_file_path - a GOES-16 or GOES-17 raw data file with 2km resolution
32  latlon_file_path - The path to the resulting IODAv2 formatted data file
33  """
34  self._source_file_path_source_file_path = source_file_path
35  self._latlon_file_path_latlon_file_path = latlon_file_path
36 
37  def _calc_latlon(self):
38  """
39  Calculates the latitude and longitude from source_file_path Dataset, reshapes the latitude and longitude
40  data arrays to a single dimension, and returns a tuple containing these data arrays.
41  """
42  source_dataset = Dataset(self._source_file_path_source_file_path, 'r')
43  source_dataset.set_auto_scale(True)
44  x = ma.getdata(source_dataset['x'][:])
45  y = ma.getdata(source_dataset['y'][:])
46  grid_x, grid_y = np.meshgrid(x, y, indexing='xy')
47  goes_imager_projection = source_dataset.variables['goes_imager_projection']
48  r_eq = goes_imager_projection.getncattr('semi_major_axis')
49  r_pol = goes_imager_projection.getncattr('semi_minor_axis')
50  h = goes_imager_projection.getncattr('perspective_point_height') + \
51  goes_imager_projection.getncattr('semi_major_axis')
52  lon_0 = goes_imager_projection.getncattr('longitude_of_projection_origin')
53  lon_0 = (lon_0 * np.pi) / 180.0
54  h_sqr = np.power(h, 2.0)
55  r_eq_sqr = np.power(r_eq, 2.0)
56  r_pol_sqr = np.power(r_pol, 2.0)
57  sin_x = np.sin(grid_x)
58  cos_x = np.cos(grid_x)
59  sin_y = np.sin(grid_y)
60  cos_y = np.cos(grid_y)
61  sin_x_sqr = np.power(sin_x, 2.0)
62  cos_x_sqr = np.power(cos_x, 2.0)
63  sin_y_sqr = np.power(sin_y, 2.0)
64  cos_y_sqr = np.power(cos_y, 2.0)
65  a = sin_x_sqr + cos_x_sqr * (cos_y_sqr + (r_eq_sqr / r_pol_sqr) * sin_y_sqr)
66  b = -2.0 * h * cos_x * cos_y
67  c = h_sqr - r_eq_sqr
68  arg = np.power(b, 2.0) - (4.0 * a * c)
69  r_s = ((-1.0 * b) - np.sqrt(arg)) / (2.0 * a)
70  s_x = r_s * cos_x * cos_y
71  s_y = (-1.0 * r_s) * sin_x
72  s_z = r_s * cos_x * sin_y
73  h_minus_s_x = h - s_x
74  s_y_sqr = np.power(s_y, 2.0)
75  h_minus_s_x_sqr = np.power(h_minus_s_x, 2.0)
76  lat = np.arctan((r_eq_sqr / r_pol_sqr) * (s_z / np.sqrt(h_minus_s_x_sqr + s_y_sqr)))
77  lon = lon_0 - np.arctan(s_y / h_minus_s_x)
78  lat = lat * 180.0 / np.pi
79  lon = lon * 180.0 / np.pi
80  lat = lat.reshape(len(lat) * len(lat))
81  lon = lon.reshape(len(lon) * len(lon))
82  lat = np.nan_to_num(lat, nan=-999)
83  lon = np.nan_to_num(lon, nan=-999)
84  yaw_flip_flag = source_dataset.variables['yaw_flip_flag'][0]
85  if not yaw_flip_flag:
86  lat = lat[::-1]
87  lon = lon[::-1]
88  source_dataset.close()
89  return lat, lon
90 
92  """
93  Returns the latitude and longitude nadir attributes from the source_file_path Dataset.
94  """
95  source_dataset = Dataset(self._source_file_path_source_file_path, 'r')
96  lat_nadir = source_dataset.variables['geospatial_lat_lon_extent'].getncattr('geospatial_lat_nadir')
97  lon_nadir = source_dataset.variables['geospatial_lat_lon_extent'].getncattr('geospatial_lon_nadir')
98  source_dataset.close()
99  return lat_nadir, lon_nadir
100 
101  def _calc_angles(self):
102  """
103  Calculates the scan and elevation angles from source_file_path Dataset, reshapes the scan and elevation angle
104  data arrays to a single dimension, and returns a tuple containing these data arrays.
105  """
106  source_dataset = Dataset(self._source_file_path_source_file_path, 'r')
107  source_dataset.set_auto_scale(True)
108  x = ma.getdata(source_dataset['x'][:])
109  y = ma.getdata(source_dataset['y'][:])
110  grid_x, grid_y = np.meshgrid(x, y, indexing='xy')
111  scan_angle = grid_x * 180.0 / np.pi
112  elevation_angle = grid_y * 180.0 / np.pi
113  scan_angle = scan_angle.reshape(len(scan_angle) * len(scan_angle))
114  elevation_angle = elevation_angle.reshape(len(elevation_angle) * len(elevation_angle))
115  yaw_flip_flag = source_dataset.variables['yaw_flip_flag'][0]
116  if not yaw_flip_flag:
117  scan_angle = scan_angle[::-1]
118  elevation_angle = elevation_angle[::-1]
119  source_dataset.close()
120  return scan_angle, elevation_angle
121 
122  def create(self):
123  """
124  Generates an IODAv2 formatted data file containing the groups, variables, attributes and dimensions listed in
125  the class header documentation.
126  """
127  latitude, longitude = self._calc_latlon_calc_latlon()
128  scan_angle, elevation_angle = self._calc_angles_calc_angles()
129  nlocs = len(latitude)
130  latlon_dataset = Dataset(self._latlon_file_path_latlon_file_path, 'w')
131  latlon_dataset.createDimension('nlocs', nlocs)
132  latlon_dataset.createVariable('nlocs', 'i4', ('nlocs',))
133  latlon_dataset.variables['nlocs'][:] = np.arange(1, nlocs + 1, 1, dtype='int32')
134  latlon_dataset.createGroup('MetaData')
135  latlon_dataset.createVariable('/MetaData/latitude', 'f4', 'nlocs', fill_value=-999)
136  latlon_dataset.createVariable('/MetaData/longitude', 'f4', 'nlocs', fill_value=-999)
137  latlon_dataset.createVariable('/MetaData/scan_angle', 'f4', 'nlocs', fill_value=-999)
138  latlon_dataset.createVariable('/MetaData/elevation_angle', 'f4', 'nlocs', fill_value=-999)
139  latlon_dataset['/MetaData/latitude'][:] = latitude
140  latlon_dataset['/MetaData/longitude'][:] = longitude
141  latlon_dataset['/MetaData/scan_angle'][:] = scan_angle
142  latlon_dataset['/MetaData/elevation_angle'][:] = elevation_angle
143  lat_nadir, lon_nadir = self._get_nadir_attributes_get_nadir_attributes()
144  latlon_dataset['/MetaData/latitude'].setncattr('lat_nadir', lat_nadir)
145  latlon_dataset['/MetaData/longitude'].setncattr('lon_nadir', lon_nadir)
146  latlon_dataset.close()
def _get_nadir_attributes(self)
Definition: goes_latlon.py:91
def __init__(self, source_file_path, latlon_file_path)
Definition: goes_latlon.py:28