IODA Bundle
viirs_modis_l3_oc2ioda.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 #
4 # (C) Copyright 2021 UCAR
5 #
6 # This software is licensed under the terms of the Apache Licence Version 2.0
7 # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
8 #
9 
10 from __future__ import print_function
11 import sys
12 import argparse
13 import netCDF4 as nc
14 from datetime import datetime, timedelta
15 import os
16 import numpy as np
17 from pathlib import Path
18 
19 IODA_CONV_PATH = Path(__file__).parent/"@SCRIPT_LIB_PATH@"
20 if not IODA_CONV_PATH.is_dir():
21  IODA_CONV_PATH = Path(__file__).parent/'..'/'lib-python'
22 sys.path.append(str(IODA_CONV_PATH.resolve()))
23 
24 import ioda_conv_ncio as iconv
25 from orddicts import DefaultOrderedDict
26 
27 
28 vName = {
29  'chlor_a': "mass_concentration_of_chlorophyll_in_sea_water",
30 }
31 
32 locationKeyList = [
33  ("latitude", "float"),
34  ("longitude", "float"),
35  ("datetime", "string")
36 ]
37 
38 AttrData = {}
39 
40 
41 class OCL3(object):
42 
43  def __init__(self, filename, date, thin, writer):
44  self.filenamefilename = filename
45  self.datedate = date
46  self.thinthin = thin
47  self.datadata = DefaultOrderedDict(lambda: DefaultOrderedDict(dict))
48  self.writerwriter = writer
49  self._read_read()
50 
51  def _read(self):
52  ncd = nc.Dataset(self.filenamefilename)
53  lons = ncd.variables['lon'][:].ravel()
54  lats = ncd.variables['lat'][:].ravel()
55  vals = ncd.variables['chlor_a'][:].ravel()
56  mask = vals > 0.0
57  vals = vals[mask]
58  len_grid = len(lons)*len(lats)
59  lons, lats = np.meshgrid(lons, lats, copy=False)
60  lons = lons.ravel()[mask]
61  lats = lats.ravel()[mask]
62 
63  # get global attributes
64  for v in ('platform', 'instrument', 'processing_version',
65  'time_coverage_start'):
66  AttrData[v] = ncd.getncattr(v)
67  ncd.close()
68 
69  valKey = vName['chlor_a'], self.writerwriter.OvalName()
70  errKey = vName['chlor_a'], self.writerwriter.OerrName()
71  qcKey = vName['chlor_a'], self.writerwriter.OqcName()
72 
73  # apply thinning mask
74  if self.thinthin > 0.0:
75  mask_thin = np.random.uniform(size=len(lons)) > self.thinthin
76  lons = lons[mask_thin]
77  lats = lats[mask_thin]
78  vals = vals[mask_thin]
79 
80  count = 0
81  for i in range(len(vals)):
82  count += 1
83  locKey = lats[i], lons[i], AttrData['time_coverage_start']
84  self.datadata[0][locKey][valKey] = vals[i]
85  self.datadata[0][locKey][errKey] = vals[i] * 0.25
86  self.datadata[0][locKey][qcKey] = 0
87 
88 
89 def main():
90 
91  parser = argparse.ArgumentParser(
92  description=('Read VIIRS/MODIS L3 standard mapped chlor_a files'
93  ' and convert to IODA format')
94  )
95  parser.add_argument('-i', '--input',
96  help="name of L3 standard mapped chlor_a input file",
97  type=str, required=True)
98  parser.add_argument('-o', '--output',
99  help="name of ioda output file",
100  type=str, required=True)
101  parser.add_argument('-d', '--date', metavar="YYYYMMDDHH",
102  help="base date for the center of the window",
103  type=str, required=True)
104  parser.add_argument('-t', '--thin',
105  help="percentage of random thinning, from 0.0 to 1.0. Zero indicates"
106  " no thinning is performed. (default: %(default)s)",
107  type=float, required=False, default=0.0)
108  args = parser.parse_args()
109  fdate = datetime.strptime(args.date, '%Y%m%d%H')
110  writer = iconv.NcWriter(args.output, locationKeyList)
111 
112  # Read in the data
113  chl = OCL3(args.input, fdate, args.thin, writer)
114 
115  # write them out
116  AttrData['date_time_string'] = fdate.strftime("%Y-%m-%dT%H:%M:%SZ")
117  AttrData['thinning'] = args.thin
118  AttrData['converter'] = os.path.basename(__file__)
119 
120  (ObsVars, LocMdata, VarMdata) = writer.ExtractObsData(chl.data)
121  writer.BuildNetcdf(ObsVars, LocMdata, VarMdata, AttrData)
122 
123 
124 if __name__ == '__main__':
125  main()
def __init__(self, filename, date, thin, writer)