OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
extract_band.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 """
4 
5 Program to extract a band (Variable) from one OBPG netCDF4 L2 file and create
6 a new file containing just that band.
7 
8 The program is also meant to serve as an example of how OBPG files in netCDF4
9 format can be accessed and manipulated.
10 
11 Helpful link:
12  http://schubert.atmos.colostate.edu/~cslocum/netcdf_example.html
13 
14 """
15 
16 import argparse
17 import os
18 import sys
19 import time
20 import traceback
21 import netCDF4 as nc
22 
23 __version__ = '1.0.1_2016-10-18'
24 
25 def copy_attribute(attr, in_group, out_group):
26  """
27  Copies the attribute named in attr from in_group to out_group.
28 
29  The checks for unicode data are needed because netCDF stores its data in
30  Unicode. However, setncattr will prepend "string" to the attributes if
31  they are unicode values. A long discussion of this appears at:
32  https://github.com/Unidata/netcdf4-python/pull/389
33  """
34  attr_val = in_group.getncattr(attr)
35  if isinstance(attr, unicode):
36  attr = str(attr)
37  if isinstance(attr_val, unicode):
38  attr_val = str(attr_val)
39  out_group.setncattr(attr, attr_val)
40 
41 def copy_variable(src_var, src_grp, dest_grp):
42  """
43  Copies the netCDF4 Variable held in src_var from the src_grp Group to the
44  dest_grp Group.
45  """
46  var_name = src_var[0]
47  var_type = src_var[1].datatype
48  new_var = dest_grp.createVariable(var_name, var_type,
49  dimensions=src_var[1].dimensions)
50  var_attrs = src_var[1].ncattrs()
51  for var_attr in var_attrs:
52  copy_attribute(var_attr, src_var[1], new_var)
53  dest_grp.variables[var_name][:] =\
54  src_grp.variables[var_name][:]
55 
56 def create_subgroup(in_parent_grp, in_grp_name, out_parent_grp,
57  select_var=None):
58  """
59  Creates a Group in out_grp using cur_grp_name as the name of the created
60  Group. Then recursively does the same for any subgroups of in_grp. If
61  select_var is not None, then only that Variable will be copied into the new
62  Group; otherwise, all Variables are copied.
63  """
64  #Create the new group
65  new_grp = out_parent_grp.createGroup(in_grp_name)
66  # Copy Variables
67  grp_variables = in_parent_grp.groups[in_grp_name].variables
68  if select_var:
69  var_to_copy = grp_variables[select_var]
70  copy_variable((select_var, var_to_copy),
71  in_parent_grp.groups[in_grp_name], new_grp)
72  else:
73  for var_item in grp_variables.items():
74  if len(var_item) > 1:
75  copy_variable(var_item, in_parent_grp.groups[in_grp_name],
76  new_grp)
77 
78  # Copy Attributes
79  attrs = in_parent_grp[in_grp_name].ncattrs()
80  for attr in attrs:
81  copy_attribute(attr, in_parent_grp[in_grp_name], new_grp)
82  # Copy subgroups
83  subgroups = in_parent_grp[in_grp_name].groups
84  if len(subgroups) > 0:
85  for grp in subgroups:
86  try:
87  create_subgroup(in_parent_grp.groups[in_grp_name], grp, new_grp)
88  except AttributeError:
89  print (traceback.format_exc())
90 
91 def get_cla():
92  """
93  Returns the command line arguments: band to extract, input filename, and
94  output filename.
95  """
96  parser = argparse.ArgumentParser(description=\
97  'Extracts a band from a netCDF4 OBPG file.')
98  parser.add_argument('--version', action='version',
99  version='%(prog)s ' + __version__)
100  parser.add_argument('band', type=str, help='band to be extracted')
101  parser.add_argument('input_file', type=str, help='path to the input file')
102  parser.add_argument('output_file', type=str, help='path to the output file')
103  args = parser.parse_args()
104  arg_list = [args.band, args.input_file, args.output_file]
105  return arg_list
106 
107 def main():
108  """
109  Primary driver of the program; get command line arguments, check the files
110  specified and kick off the processing
111  """
112  args = get_cla()
113  band = args[0]
114  in_file = args[1]
115  out_file = args[2]
116  # './test/data/A2015086003500.L2_LAC_OC.nc'
117  if os.path.exists(out_file):
118  err_msg = 'Error! A file named {0} already exists!'.format(out_file)
119  sys.exit(err_msg)
120 
121  if os.path.exists(in_file):
122  with nc.Dataset(in_file) as in_dataset:
123  if band in in_dataset.groups['geophysical_data'].variables:
124  with nc.Dataset(out_file, 'w') as out_dataset:
125  process_main_dataset(in_dataset, band, out_dataset,
126  ['date_created', 'history',
127  'product_name'])
128  # Set attribute values that need to be customized.
129  cmd_line = ' '.join(sys.argv)
130  orig_history = in_dataset.getncattr('history')
131  if isinstance(orig_history, unicode):
132  orig_history = str(orig_history)
133  history_str = ' ; '.join([orig_history, cmd_line])
134  creation_date_str = time.strftime('%Y-%m-%dT%H:%M:%S.000Z',
135  time.gmtime())
136  out_dataset.setncattr('history', history_str)
137  out_dataset.setncattr('product_name', sys.argv[3])
138  out_dataset.setncattr('date_created', creation_date_str)
139  else:
140  err_msg = 'Error! Cannot locate band {0} in {1}.'.\
141  format(band, in_file)
142  sys.exit(err_msg)
143  else:
144  err_msg = 'Could NOT find {0}.'.format(in_file)
145  sys.exit(err_msg)
146 
147 def process_main_dataset(in_dataset, band, out_dataset, attrs_to_skip=None):
148  """
149  Copy the top level dimensions, Variables, and Attributes from in_dataset
150  to out_dataset. Copy Groups other than the 'geophysical_data' group. In the
151  'geophysical_data' Group, call copy_band to copy only the Variable named
152  in band.
153  """
154  for dimension in in_dataset.dimensions:
155  out_dataset.createDimension(dimension,
156  len(in_dataset.dimensions[dimension]))
157  for var in in_dataset.variables:
158  copy_variable(var, in_dataset, out_dataset)
159  global_attrs = in_dataset.ncattrs()
160  if attrs_to_skip:
161  for attr in global_attrs:
162  if not attr in attrs_to_skip:
163  copy_attribute(attr, in_dataset, out_dataset)
164  else:
165  for attr in global_attrs:
166  copy_attribute(attr, in_dataset, out_dataset)
167  top_groups = in_dataset.groups
168  for grp in top_groups:
169  if grp == 'geophysical_data':
170  create_subgroup(in_dataset, grp, out_dataset, band)
171  else:
172  create_subgroup(in_dataset, grp, out_dataset)
173 
174 # The following allows the file to be imported without immediately executing.
175 if __name__ == '__main__':
176  sys.exit(main())
def copy_variable(src_var, src_grp, dest_grp)
Definition: extract_band.py:41
def process_main_dataset(in_dataset, band, out_dataset, attrs_to_skip=None)
def copy_attribute(attr, in_group, out_group)
Definition: extract_band.py:25
def create_subgroup(in_parent_grp, in_grp_name, out_parent_grp, select_var=None)
Definition: extract_band.py:56
const char * str
Definition: l1c_msi.cpp:35