3 from seabass.SB_support
import readSB
4 from netCDF4
import Dataset
10 from collections
import OrderedDict
13 sensorDef = OrderedDict()
16 if instrument ==
'seawifs':
17 sensorDef[
'wavelength'] = [412, 443, 490, 510, 555, 670, 765, 865]
18 sensorDef[
'platform'] =
'OrbView-2'
19 sensorDef[
'instrument'] =
'SeaWiFS'
21 elif instrument ==
'octs':
22 sensorDef[
'wavelength'] = [412, 443, 490, 516, 565, 667, 765, 862]
23 sensorDef[
'platform'] =
'ADEOS'
24 sensorDef[
'instrument'] =
'OCTS'
26 elif instrument ==
'avhrr':
27 sensorDef[
'wavelength'] = [630, 855, 3700, 11000, 12000]
28 sensorDef[
'platform'] =
'AVHRR'
29 sensorDef[
'instrument'] =
'AVHRR'
31 elif instrument ==
'osmi':
32 sensorDef[
'wavelength'] = [412, 443, 490, 555, 765, 865]
33 sensorDef[
'platform'] =
'KOMPSAT'
34 sensorDef[
'instrument'] =
'OSMI'
36 elif instrument ==
'modis':
37 sensorDef[
'wavelength'] = [412,443,469,488,531,547,555,645,667,678,748,859,869,1240,1640,2130]
38 if platform ==
'aqua':
39 sensorDef[
'platform'] =
'Aqua'
41 sensorDef[
'platform'] =
'Terra'
43 sensorDef[
'instrument'] =
'MODIS'
45 elif instrument ==
'czcs':
46 sensorDef[
'wavelength'] = [443, 520, 550, 670]
47 sensorDef[
'platform'] =
'Nimbus-7'
48 sensorDef[
'instrument'] =
'CZCS'
50 elif instrument ==
'ocm':
51 sensorDef[
'wavelength'] = [414, 441, 486, 511, 556, 669, 769, 865]
52 sensorDef[
'platform'] =
'IRS-P4'
53 sensorDef[
'instrument'] =
'OCM'
55 elif instrument ==
'ocm-2':
56 sensorDef[
'wavelength'] = [415, 442, 491, 512, 557, 620, 745, 866]
57 sensorDef[
'platform'] =
'Oceansat-2'
58 sensorDef[
'instrument'] =
'OCM-2'
60 elif instrument ==
'meris':
61 sensorDef[
'wavelength'] = [413, 443, 490, 510, 560, 620, 665, 681, 709, 754, 762, 779, 865, 885, 900]
62 sensorDef[
'platform'] =
'Envisat'
63 sensorDef[
'instrument'] =
'MERIS'
65 elif instrument ==
'viirs':
66 sensorDef[
'wavelength'] = [410, 443, 486, 551, 671, 745, 862, 1238, 1601, 2257]
67 sensorDef[
'platform'] =
'Suomi-NPP'
68 sensorDef[
'instrument'] =
'VIIRS'
70 elif instrument ==
'ocrvc':
71 sensorDef[
'wavelength'] = [412, 443, 490, 510, 531, 555, 670]
72 sensorDef[
'platform'] =
'OCRVC'
73 sensorDef[
'instrument'] =
'OCRVC'
75 elif instrument ==
'hico':
76 sensorDef[
'wavelength'] = [353, 358, 364, 370, 375, 381, 387, 393, 398, 404, 410, 416, 421, 427, 433, 438, 444, 450, 456, 461, 467, 473, 479, 484, 490, 496, 501, 507, 513, 519, 524, 530, 536, 542, 547, 553, 559, 564, 570, 576, 582, 587, 593, 599, 605, 610, 616, 622, 627, 633, 639, 645, 650, 656, 662, 668, 673, 679, 685, 690, 696, 702, 708, 713, 719, 725, 731, 736, 742, 748, 753, 759, 765, 771, 776, 782, 788, 794, 799, 805, 811, 816, 822, 828, 834, 839, 845, 851, 857, 862, 868, 874, 880, 885, 891, 897, 902, 908, 914, 920, 925, 931, 937, 943, 948, 954, 960, 965, 971, 977, 983, 988, 994, 1000, 1006, 1011, 1017, 1023, 1028, 1034, 1040, 1046, 1051, 1057, 1063, 1069, 1074, 1080]
77 sensorDef[
'platform'] =
'ISS'
78 sensorDef[
'instrument'] =
'HICO'
80 elif instrument ==
'goci':
81 sensorDef[
'wavelength'] = [412, 443, 490, 555, 660, 680, 745, 865]
82 sensorDef[
'platform'] =
'COMS'
83 sensorDef[
'instrument'] =
'GOCI'
85 elif instrument ==
'oli':
86 sensorDef[
'wavelength'] = [443, 482, 561, 655, 865, 1609, 2201]
87 sensorDef[
'platform'] =
'Landsat-8'
88 sensorDef[
'instrument'] =
'OLI'
90 elif instrument ==
'ocia':
91 sensorDef[
'wavelength'] = [366, 376, 385, 395, 405, 414, 424, 434, 443, 453, 463, 472, 482, 492, 502, 511, 521, 531, 541, 550, 560, 570, 580, 589, 599, 609, 619, 628, 638, 648, 658, 665, 674, 684, 694, 704, 714, 723, 733, 743, 753, 762, 772, 782, 792, 801, 811, 821, 831, 840, 850, 860, 869, 879, 889, 937, 1239, 1382, 1642, 2127, 2247]
92 sensorDef[
'platform'] =
'PACE'
93 sensorDef[
'instrument'] =
'OCIA"'
95 elif instrument ==
'averis':
96 sensorDef[
'wavelength'] = [366, 376, 385, 395, 405, 414, 424, 434, 443, 453, 463, 472, 482, 492, 502, 511, 521, 531, 541, 550, 560, 570, 580, 589, 599, 609, 619, 628, 638, 648, 658, 665, 674, 684, 694, 704, 714, 723, 733, 743, 753, 762, 772, 782, 792, 801, 811, 821, 831, 840, 850, 860, 869, 879, 889, 898, 908, 918, 927, 937, 947, 956, 966, 976, 985, 995, 1005, 1014, 1024, 1033, 1043, 1053, 1062, 1072, 1081, 1091, 1101, 1110, 1120, 1129, 1139, 1148, 1158, 1167, 1177, 1186, 1196, 1205, 1215, 1224, 1234, 1243, 1253, 1263, 1273, 1283, 1293, 1303, 1313, 1323, 1333, 1343, 1352, 1362, 1372, 1382, 1392, 1402, 1412, 1422, 1432, 1442, 1452, 1462, 1472, 1482, 1492, 1502, 1512, 1522, 1532, 1542, 1552, 1562, 1572, 1582, 1592, 1602, 1612, 1622, 1632, 1642, 1651, 1661, 1671, 1681, 1691, 1701, 1711, 1721, 1731, 1741, 1751, 1761, 1771, 1781, 1791, 1801, 1811, 1821, 1831, 1841, 1851, 1861, 1871, 1876, 1886, 1896, 1906, 1916, 1926, 1936, 1946, 1956, 1966, 1977, 1987, 1997, 2007, 2017, 2027, 2037, 2047, 2057, 2067, 2077, 2087, 2097, 2107, 2117, 2127, 2137, 2147, 2157, 2167, 2177, 2187, 2197, 2207, 2217, 2227, 2237, 2247, 2257, 2267, 2277, 2287, 2297, 2306, 2316]
97 sensorDef[
'platform'] =
'AVIRIS'
98 sensorDef[
'instrument'] =
'AVIRIS'
100 elif instrument ==
'prism':
101 sensorDef[
'wavelength'] = [350.357208, 361.678589, 373.000854, 384.324005, 395.648071, 406.973022, 418.298889, 429.625671, 440.953308, 452.281891, 463.611359, 474.941711, 486.27298, 497.605133, 508.938202, 520.272156, 531.606995, 542.94281, 554.279419, 565.617004, 576.955444, 588.2948, 599.635071, 610.976257, 622.318298, 633.661255, 645.005127, 656.349915, 667.695557, 679.042114, 690.389587, 701.737915, 713.087158, 724.437317, 735.788391, 747.140381, 758.493225, 769.846985, 781.20166, 792.55719, 803.913635, 815.270996, 826.629272, 837.988403]
102 sensorDef[
'platform'] =
'PRISM'
103 sensorDef[
'instrument'] =
'PRISM'
105 elif instrument ==
'olci':
106 sensorDef[
'wavelength'] = [400, 412, 442, 490, 510, 560, 620, 665, 674, 681, 709, 754, 761, 764, 768, 779, 865, 885, 900, 940, 1012]
107 sensorDef[
'platform'] =
'Sentinel-3'
108 sensorDef[
'instrument'] =
'OLCI'
110 elif instrument ==
'sgli':
111 sensorDef[
'wavelength'] = [380, 412, 443, 490, 529, 566, 672, 763, 867, 1055, 1385, 1634, 2211]
112 sensorDef[
'platform'] =
'GCOM_C'
113 sensorDef[
'instrument'] =
'SGLI'
115 elif instrument ==
'msi':
116 sensorDef[
'wavelength'] = [444, 497, 560, 664, 704, 740, 783, 837, 865, 945, 1374, 1613, 2200]
117 sensorDef[
'platform'] =
'Sentinel-2A'
118 sensorDef[
'instrument'] =
'MSI'
121 sys.exit(
"Instrument not supported: %s (%s)" % (instrument,platform))
126 parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
128 This program takes a specially-crafted SeaBASS formatted file and outputs
129 an L1B file which can be read by the l2gen program. Below is an example
130 file with comments explaining things.
137 ! This is a test input file for the seabass2L1B.py script.
138 ! The file format is defined at:
140 ! https://seabass.gsfc.nasa.gov/wiki/Data_Submission#Data Format
143 ! instrument = SeaWiFS, OCTS, AVHRR, OSMI, MODIS, CZCS, OCM, OCM-2, MERIS, VIIRS,
144 ! OCRVC, HICO, GOCI, OLI, OCIA, AVIRIS, PRISM, OLCI, SGLI, MSI
145 ! platform = Aqua, Terra
151 ! pixels_per_line = if supplied the data is wrapped into a 2D file instead of
152 ! one pixel per line in the L1B file.
153 ! pixnum = comma delimited array, "pixels_per_line" in length
170 ! required fields are:
171 ! Lt_nnn = (W m^-2 um^-1 sr^-1) an Lt field is required for each wavelength of
172 ! the selected sensor.
175 ! scantime = unix time (double, secs since 1970), takes precedence over
176 ! date,time. If neither scantime nor date,time exist then
177 ! start_date, start_time header is used.
198 /start_time=16:01:30[GMT]
199 /north_latitude=-46.797[DEG]
200 /east_longitude=-95.561[DEG]
207 /fields=Lt_412,Lt_443,Lt_469,Lt_488,Lt_531,Lt_547,Lt_555,Lt_645,Lt_667,Lt_678,Lt_748,Lt_859,Lt_869,Lt_1240,Lt_1640,Lt_2130
209 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
210 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
211 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
212 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
213 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
214 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
215 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
216 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
217 61.86 54.37 50.11 40.83 26.54 23.22 21.63 10.78 9.70 9.09 6.03 3.3 3.17 .84 .34 .09
220 The argument-list is a set of keyword=value pairs.
223 parser.add_argument(
'-ifile', nargs=1, type=str, help=
'input SeaBASS file')
224 parser.add_argument(
'-ofile', nargs=1, type=str, help=
'output L1B file name ')
226 args=parser.parse_args()
228 if not dict_args[
'ifile']
or not dict_args[
'ofile']:
229 parser.error(
"you must specify an input file and an output file")
231 ifileName = dict_args[
'ifile'][0]
232 ofileName = dict_args[
'ofile'][0]
234 ds = readSB(filename=ifileName, mask_missing=
False, mask_above_detection_limit=
False,
235 mask_below_detection_limit=
False, no_warn=
True)
238 if 'instrument' not in ds.headers:
239 sys.exit(
'Error: Must include "instrument" in the headers.')
240 if 'platform' not in ds.headers:
241 sys.exit(
'Error: Must include "platform" in the headers.')
242 if 'missing' not in ds.headers:
243 sys.exit(
'Error: Must include "missing" in the headers.')
244 if 'delimiter' not in ds.headers:
245 sys.exit(
'Error: Must include "delimiter" in the headers.')
246 if 'fields' not in ds.headers:
247 sys.exit(
'Error: Must include "fields" in the headers.')
249 sensorDef =
getSensorDefs(ds.headers[
'instrument'], ds.headers[
'platform'])
250 sensorWavelengths = sensorDef[
'wavelength']
252 for wave
in sensorWavelengths:
253 sensorBandNames.append(
"Lt_" +
str(wave))
255 fieldNames =
list(ds.data.keys())
256 numPixels = len(ds.data[fieldNames[0]])
259 pixelsPerLine =
int(ds.headers[
'pixels_per_line'])
262 numLines =
int(numPixels / pixelsPerLine)
269 lat = np.full((numLines,pixelsPerLine),
float((ds.headers[
'north_latitude'].split(
'['))[0]))
271 sys.exit(
'Error: Must include "north_latitude" in the header or "lat" in the data block')
278 lon = np.full((numLines,pixelsPerLine),
float((ds.headers[
'east_longitude'].split(
'['))[0]))
280 sys.exit(
'Error: Must include "east_longitude" in the header or "lon" in the data block')
284 solz = ds.data[
'solz']
287 solz = np.full((numLines, pixelsPerLine), ds.headers[
'solz'])
293 sola = ds.data[
'sola']
296 sola = np.full((numLines, pixelsPerLine), ds.headers[
'sola'])
302 senz = ds.data[
'senz']
305 senz = np.full((numLines, pixelsPerLine), ds.headers[
'senz'])
307 sys.exit(
'Error: Must include "senz" in the header or in the data block')
311 sena = ds.data[
'sena']
314 sena = np.full((numLines, pixelsPerLine), ds.headers[
'sena'])
316 sys.exit(
'Error: Must include "sena" in the header or in the data block')
320 pixnum = [
int(x)
for x
in ds.headers[
'pixnum'].split(
",") ]
326 windspeed = ds.data[
'windspeed']
329 windspeed = np.full((numLines, pixelsPerLine), ds.headers[
'windspeed'])
335 windangle = ds.data[
'windangle']
338 windangle = np.full((numLines, pixelsPerLine), ds.headers[
'windangle'])
344 pressure = ds.data[
'pressure']
347 pressure = np.full((numLines, pixelsPerLine), ds.headers[
'pressure'])
353 ozone = ds.data[
'ozone']
356 ozone = np.full((numLines, pixelsPerLine), ds.headers[
'ozone'])
362 relhumid = ds.data[
'relhumid']
365 relhumid = np.full((numLines, pixelsPerLine), ds.headers[
'relhumid'])
371 watervapor = ds.data[
'watervapor']
374 watervapor = np.full((numLines, pixelsPerLine), ds.headers[
'watervapor'])
380 if os.path.exists(ofileName):
383 ncfile = Dataset(ofileName,
"w", format=
"NETCDF4")
385 ncfile.createDimension(
'number_of_lines', numLines)
386 ncfile.createDimension(
'pixels_per_line', pixelsPerLine)
387 ncfile.createDimension(
'number_of_bands', len(sensorWavelengths))
389 sensorgrp = ncfile.createGroup(
'sensor_band_parameters')
390 scangrp = ncfile.createGroup(
'scan_line_attributes')
391 datagrp = ncfile.createGroup(
'geophysical_data')
392 navgrp = ncfile.createGroup(
'navigation_data')
395 ncfile.title = (sensorDef[
'instrument'] +
' Level-1B').encode(
"ascii")
396 ncfile.instrument = sensorDef[
'instrument'].encode(
"ascii")
397 ncfile.platform = sensorDef[
'platform'].encode(
"ascii")
398 ncfile.processing_level =
'L1B'.encode(
"ascii")
399 ncfile.date_created = (datetime.datetime.utcnow().isoformat()).encode(
"ascii")
400 ncfile.history = (
' '.join(sys.argv)).encode(
"ascii")
403 sensorgrp.createVariable(
'wavelength',
'i', (
'number_of_bands'), fill_value=-32767)
404 sensorgrp.createVariable(
'F0',
'f', (
'number_of_bands'), fill_value=-32767)
405 sensorgrp.createVariable(
'Tau_r',
'f', (
'number_of_bands'), fill_value=-32767)
406 sensorgrp.createVariable(
'k_oz',
'f', (
'number_of_bands'), fill_value=-32767)
407 sensorgrp.createVariable(
't_co2',
'f', (
'number_of_bands'), fill_value=-32767)
408 sensorgrp.createVariable(
'k_no2',
'f', (
'number_of_bands'), fill_value=-32767)
409 sensorgrp.createVariable(
'a_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
410 sensorgrp.createVariable(
'b_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
411 sensorgrp.createVariable(
'c_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
412 sensorgrp.createVariable(
'd_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
413 sensorgrp.createVariable(
'e_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
414 sensorgrp.createVariable(
'f_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
415 sensorgrp.createVariable(
'g_h2o',
'f', (
'number_of_bands'), fill_value=-32767)
416 sensorgrp.createVariable(
'awhite',
'f', (
'number_of_bands'), fill_value=-32767)
417 sensorgrp.createVariable(
'aw',
'f', (
'number_of_bands'), fill_value=-32767)
418 sensorgrp.createVariable(
'bbw',
'f', (
'number_of_bands'), fill_value=-32767)
420 sensorgrp.createVariable(
'pixnum',
'i', (
'pixels_per_line'), fill_value=-32767)
423 scangrp.createVariable(
'scantime',
'd', (
'number_of_lines'), fill_value=-32767)
426 for varName
in sensorBandNames:
427 datagrp.createVariable(varName,
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
430 navgrp.createVariable(
'longitude',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
431 navgrp.createVariable(
'latitude',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
432 navgrp.createVariable(
'senz',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
433 navgrp.createVariable(
'sena',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
435 navgrp.createVariable(
'solz',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
436 navgrp.createVariable(
'sola',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
439 if len(windspeed)
or len(windangle)
or len(pressure)
or len(ozone)
or len(relhumid)
or len(watervapor):
440 ancillarygrp = ncfile.createGroup(
'ancillary_data')
442 ancillarygrp.createVariable(
'windspeed',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
444 ancillarygrp.createVariable(
'windangle',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
446 ancillarygrp.createVariable(
'pressure',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
448 ancillarygrp.createVariable(
'ozone',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
450 ancillarygrp.createVariable(
'relhumid',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
452 ancillarygrp.createVariable(
'watervapor',
'f', (
'number_of_lines',
'pixels_per_line'), fill_value=-32767)
461 ancillarygrp.variables[
'windspeed'][:] = windspeed
463 ancillarygrp.variables[
'windangle'][:] = windangle
465 ancillarygrp.variables[
'pressure'][:] = pressure
467 ancillarygrp.variables[
'ozone'][:] = ozone
469 ancillarygrp.variables[
'relhumid'][:] = relhumid
471 ancillarygrp.variables[
'watervapor'][:] = watervapor
474 sensorgrp.variables[
'wavelength'][:] = sensorWavelengths
477 sensorgrp.variables[
'pixnum'][:] = pixnum
479 sys.exit(
'Error: "pixnum" must have have a length of "pixels_per_line"')
481 if 'scantime' in fieldNames:
483 scangrp.variables[
'scantime'][:] = ds.data[
'scantime'][::pixelsPerLine]
485 sys.exit(
'Error: the number of lines in the data section must be a multiple of "pixels_per_line"')
488 scantime = np.array([(
lambda scantime: [dt.timestamp()])(dt)
for dt
in ds.fd_datetime()])
490 scangrp.variables[
'scantime'][:] = scantime[::pixelsPerLine]
492 sys.exit(
'Error: the number of lines in the data section must be a multiple of "pixels_per_line"')
495 for varName
in sensorBandNames:
496 datagrp.variables[varName][:] = ds.data[varName.lower()]
498 navgrp.variables[
'latitude'][:] = lat
499 navgrp.variables[
'longitude'][:] = lon
500 navgrp.variables[
'senz'][:] = senz
501 navgrp.variables[
'sena'][:] = sena
504 navgrp.variables[
'solz'][:] = solz
505 navgrp.variables[
'sola'][:] = sola
509 if __name__ ==
"__main__":
main()