6 from datetime
import datetime, timedelta
11 from shutil
import copyfile
as cp
12 import xml.etree.ElementTree
as ET
19 tree = ET.parse(manifestfile)
24 for child
in root.find(
'dataObjectSection'):
25 filename = pathlib.PurePath(child.find(
'byteStream').find(
'fileLocation').attrib[
'href']).name
26 if 'radiance' in filename:
27 radfiles.append(filename)
28 elif 'tie_' in filename:
29 tiefiles.append(filename)
30 elif 'time_coordinates' in filename:
33 engfiles.append(filename)
35 return (radfiles, tiefiles, engfiles)
38 return arr.min(), arr.max()
42 base = datetime(2000, 1, 1, 0, 0, 0)
43 t = base + timedelta(microseconds=
int(usec))
44 return t.strftime(
'%Y-%m-%dT%H:%M:%S.%fZ')
49 north=None, south=None, west=None, east=None,
50 spixl=None, epixl=None, sline=None, eline=None,
53 self.
idir = pathlib.Path(idir)
54 self.
odir = pathlib.Path(odir)
82 for filename
in files:
83 srcfile = self.
idir / filename
85 dstfile = self.
odir / filename
87 print(
'Extracting', srcfile)
92 with netCDF4.Dataset(dstfile, mode=
'a')
as dst:
93 dst.setncatts(self.
attrs)
98 print(
"north={} south={} west={} east={}".
106 pl.lonlat2pixline(zero=
False)
108 (pl.spixl, pl.epixl, pl.sline, pl.eline)
118 self.
odir =
'.'.join([self.
idir,
'subset'])
119 pathlib.Path(self.
odir).mkdir(parents=
True, exist_ok=
True)
122 with netCDF4.Dataset(self.
tiefile,
'r')
as src:
123 npixl = src.dimensions[
'tie_columns'].size
124 nline = src.dimensions[
'tie_rows'].size
125 dpixl = getattr(src,
'ac_subsampling_factor', 1)
126 dline = getattr(src,
'al_subsampling_factor', 1)
127 spixl, epixl = [self.
spixl, self.
epixl + dpixl - 1] // dpixl
128 sline, eline = [self.
sline, self.
eline + dline - 1] // dline
135 pixls_needed = points_required - (epixl - spixl + 1)
137 spixl = max(0, spixl - pixls_needed // 2)
138 epixl = min(spixl + points_required, npixl) - 1
139 if epixl == npixl - 1:
140 spixl = npixl - points_required
142 lines_needed = points_required - (eline - sline + 1)
144 sline = max(0, sline - lines_needed // 2)
145 eline = min(sline + points_required, nline) - 1
146 if eline == nline - 1:
147 sline = nline - points_required
151 spixl, epixl = [dpixl*v
for v
in (spixl, epixl)]
152 sline, eline = [dline*v
for v
in (sline, eline)]
154 print(
"spixl={} epixl={} sline={} eline={}".
155 format(spixl+1, epixl+1, sline+1, eline+1))
158 with netCDF4.Dataset(self.
timefile,
'r')
as src:
159 ts = src[
'time_stamp'][[sline, eline]]
164 with netCDF4.Dataset(self.
geofile,
'r')
as src:
165 lat_min, lat_max =
minmax(src[
'latitude']
166 [sline:eline, spixl:epixl])
167 lon_min, lon_max =
minmax(src[
'longitude']
168 [sline:eline, spixl:epixl])
171 self.
attrs = {
'start_time': start_time,
172 'stop_time': stop_time,
173 'geospatial_lat_min': lat_min,
174 'geospatial_lat_max': lat_max,
175 'geospatial_lon_min': lon_min,
176 'geospatial_lon_max': lon_max }
180 subset = {
'rows': [sline, eline]}
184 subset = {
'columns':[spixl, epixl],
185 'rows': [sline, eline]}
187 status += self.
runextract(radfiles + engfiles, subset)
190 subset = {
'tie_columns':[spixl, epixl] // dpixl,
191 'tie_rows': [sline, eline] // dline}
197 if __name__ ==
"__main__":
200 parser = argparse.ArgumentParser(
201 description=
'Extract specified area from OLCI Level 1B files.',
202 epilog=
'Specify either geographic limits or pixel/line ranges, not both.')
203 parser.add_argument(
'-v',
'--verbose', help=
'print status messages',
205 parser.add_argument(
'idir',
206 help=
'directory containing OLCI Level 1B files')
207 parser.add_argument(
'odir', nargs=
'?',
208 help=
'output directory (defaults to "idir.subset")')
210 group1 = parser.add_argument_group(
'geographic limits')
211 group1.add_argument(
'-n',
'--north', type=float, help=
'northernmost latitude')
212 group1.add_argument(
'-s',
'--south', type=float, help=
'southernmost latitude')
213 group1.add_argument(
'-w',
'--west', type=float, help=
'westernmost longitude')
214 group1.add_argument(
'-e',
'--east', type=float, help=
'easternmost longitude')
216 group2 = parser.add_argument_group(
'pixel/line ranges (1-based)')
217 group2.add_argument(
'--spixl', type=int, help=
'start pixel')
218 group2.add_argument(
'--epixl', type=int, help=
'end pixel')
219 group2.add_argument(
'--sline', type=int, help=
'start line')
220 group2.add_argument(
'--eline', type=int, help=
'end line')
222 if len(sys.argv) == 1:
225 args = parser.parse_args()
238 verbose=args.verbose)
241 if not this.idir.exists():
242 print(
"ERROR: Directory '{}' does not exist. Exiting.".format(this.idir))
244 if not this.timefile.exists():
245 print(
"ERROR: Timestamp file ({}) not found!".format(this.timefile))
247 if not this.geofile.exists():
248 print(
"ERROR: Geolocation file ({}) not found!".format(this.geofile))
250 if not this.tiefile.exists():
251 print(
"ERROR: Tie file ({}) not found!".format(this.tiefile))
255 goodlatlons =
None not in (this.north, this.south, this.west, this.east)
256 goodindices =
None not in (this.spixl, this.epixl, this.sline, this.eline)
257 if (goodlatlons
and goodindices):
258 print(
"ERROR: Specify either geographic limits or pixel/line ranges, not both.")
261 status = this.getpixlin()
262 if status
not in (0, 110):
263 print(
"No extract; lonlat2pixline status =", status)
268 print(
"ERROR: Specify all values for either geographic limits or pixel/line ranges.")
275 cp(this.manifest, this.odir /
'xfdumanifest.xml')