gdar-sar 1.2.0.post3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gdar/io/geoid_height_grid_EGM96.tif +0 -0
- gdar/io/gsar_info.py +657 -0
- gdar/io/legacy_format.py +376 -0
- gdar/io/sentinel1.py +1605 -0
- gdar/io/sentinel1_orbit.py +557 -0
- gdar/io/simplecrs.py +386 -0
- gdar/io/util.py +148 -0
- gdar/sar/__init__.py +1 -0
- gdar/sar/bistatic_geometry.py +766 -0
- gdar/sar/crs_tools.py +63 -0
- gdar/sar/meta.py +269 -0
- gdar/sar/metatools.py +59 -0
- gdar/sar/rastertools.py +1329 -0
- gdar/sar/refsys.py +714 -0
- gdar/sar_utils.py +56 -0
- gdar_sar-1.2.0.post3.dist-info/METADATA +200 -0
- gdar_sar-1.2.0.post3.dist-info/RECORD +19 -0
- gdar_sar-1.2.0.post3.dist-info/WHEEL +4 -0
- gdar_sar-1.2.0.post3.dist-info/licenses/LICENSE +202 -0
|
Binary file
|
gdar/io/gsar_info.py
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# :encoding=utf-8
|
|
3
|
+
|
|
4
|
+
import copy
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from gdar.base import base, gtime
|
|
10
|
+
from gdar.base.dtype import value_from_dtype
|
|
11
|
+
from gdar.base.meta import make_meta, make_refsys
|
|
12
|
+
from gdar.io.util import add_slc_processing_to_meta
|
|
13
|
+
|
|
14
|
+
IDL_type_map = (
|
|
15
|
+
None, # 0 used for no-data files
|
|
16
|
+
np.uint8, # 1
|
|
17
|
+
np.int16, # 2 signed short
|
|
18
|
+
np.int32, # 3 signed long
|
|
19
|
+
np.float32, # 4 single
|
|
20
|
+
np.float64, # 5 double
|
|
21
|
+
np.complex64, # 6 single-precision complex
|
|
22
|
+
None, # 7
|
|
23
|
+
None, # 8
|
|
24
|
+
np.complex128, # 9 double-precision complex
|
|
25
|
+
None, # 10
|
|
26
|
+
None, # 11
|
|
27
|
+
np.uint16, # 12 unsigned short
|
|
28
|
+
np.uint32, # 13 unsigned long
|
|
29
|
+
np.int64, # 14 signed long long
|
|
30
|
+
np.uint64, # 15 unsigned long long
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def lc_keys(dct):
|
|
35
|
+
# return dict([(k.lower(), dct[k]) for k in dct])
|
|
36
|
+
d = {}
|
|
37
|
+
for k in dct:
|
|
38
|
+
v = dct[k]
|
|
39
|
+
k = k.lower()
|
|
40
|
+
if k == "ytime":
|
|
41
|
+
if type(v) is list:
|
|
42
|
+
v = np.array(v, dtype="datetime64[ns]")
|
|
43
|
+
else:
|
|
44
|
+
v = np.datetime64(v, "ns")
|
|
45
|
+
d[k] = v
|
|
46
|
+
return d
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def to_dtype(value):
|
|
50
|
+
if type(value) is str:
|
|
51
|
+
return (np.dtype(np.datetime64(value, "ns")),)
|
|
52
|
+
if type(value) is np.ndarray:
|
|
53
|
+
return value.dtype, value.shape
|
|
54
|
+
|
|
55
|
+
return (np.dtype(type(value)),)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _decode_idl_value(value):
|
|
59
|
+
"""Internal function for odict_from_idl_xml()"""
|
|
60
|
+
|
|
61
|
+
if isinstance(value, list):
|
|
62
|
+
return [_decode_idl_value(x) for x in value]
|
|
63
|
+
if not isinstance(value, OrderedDict):
|
|
64
|
+
return value
|
|
65
|
+
if "@IDLtype" not in value:
|
|
66
|
+
return value
|
|
67
|
+
# raise ValueError('XML not written by IDL XML2STRUCT')
|
|
68
|
+
itype = value["@IDLtype"]
|
|
69
|
+
if itype == "struct":
|
|
70
|
+
if "@IDLsize" in value:
|
|
71
|
+
# Array of structures. Create dtype first:
|
|
72
|
+
dtp = np.dtype([(kk,) + to_dtype(vv) for kk, vv in value["item"][0].items()])
|
|
73
|
+
# raise NotImplementedError('Arrays of structures'+
|
|
74
|
+
# 'not implemented yet')
|
|
75
|
+
val = np.ndarray(int(value["@IDLsize"]), dtype=dtp)
|
|
76
|
+
for name in dtp.names:
|
|
77
|
+
val[name] = np.array([v[name] for v in value["item"]])
|
|
78
|
+
return val
|
|
79
|
+
|
|
80
|
+
val = OrderedDict([(k, _decode_idl_value(value[k])) for k in value if k[0] != "@"])
|
|
81
|
+
return val
|
|
82
|
+
if itype == "string":
|
|
83
|
+
if "@IDLsize" in value:
|
|
84
|
+
val = np.array([_decode_idl_value(x) for x in value["item"]])
|
|
85
|
+
else:
|
|
86
|
+
val = value["#text"] if "#text" in value else ""
|
|
87
|
+
return val
|
|
88
|
+
if itype in ["int", "uint", "long", "ulong", "float", "double", "ulong64"]:
|
|
89
|
+
if itype in ["ulong", "ulong64"]:
|
|
90
|
+
itype = "uint"
|
|
91
|
+
val = np.fromstring(value["#text"], dtype=itype, sep=" ")
|
|
92
|
+
elif itype in ["complex", "dcomplex"]:
|
|
93
|
+
val = np.fromstring(value["#text"], dtype="double", sep=" ").view("complex")
|
|
94
|
+
else:
|
|
95
|
+
raise ValueError("IDLtype: " + itype + " not recognized")
|
|
96
|
+
|
|
97
|
+
if "@IDLsize" in value:
|
|
98
|
+
val.shape = np.fromstring(value["@IDLsize"], dtype="int", sep=" ")[::-1]
|
|
99
|
+
elif val.shape == (1,):
|
|
100
|
+
val = val[0]
|
|
101
|
+
return val
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ======================= gdar_info.meta_from_info: ==========================
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _instrument_substructure(iii):
|
|
108
|
+
platform = iii.pop("platform", "")
|
|
109
|
+
|
|
110
|
+
if "product" in iii:
|
|
111
|
+
product = iii.pop("product").split("-")
|
|
112
|
+
if len(product) > 1:
|
|
113
|
+
swath = product[-1]
|
|
114
|
+
mode = ""
|
|
115
|
+
for field in product[0:-1]:
|
|
116
|
+
mode += field
|
|
117
|
+
else:
|
|
118
|
+
if platform[:2] == "S1":
|
|
119
|
+
swath = product[0]
|
|
120
|
+
mode = swath[:-1]
|
|
121
|
+
else:
|
|
122
|
+
swath = ""
|
|
123
|
+
mode = product[0]
|
|
124
|
+
else:
|
|
125
|
+
mode, swath = "", ""
|
|
126
|
+
|
|
127
|
+
meta_instrument = {
|
|
128
|
+
"platform": platform,
|
|
129
|
+
"mode": mode,
|
|
130
|
+
"swath": swath,
|
|
131
|
+
"radarfreq": iii.pop("radarfreq", ""),
|
|
132
|
+
"polarization": iii.pop("polarization", ""),
|
|
133
|
+
"leftlooking": iii.pop("leftlooking", 0),
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if "antenna" in iii:
|
|
137
|
+
meta_instrument["antenna"] = iii.pop("antenna")
|
|
138
|
+
if "npannels" in meta_instrument["antenna"]:
|
|
139
|
+
meta_instrument["antenna"]["npanels"] = meta_instrument["antenna"].pop("npannels")
|
|
140
|
+
if "npanels" not in meta_instrument["antenna"]:
|
|
141
|
+
meta_instrument["antenna"]["npanels"] = 14
|
|
142
|
+
|
|
143
|
+
else:
|
|
144
|
+
if platform == "ALOS":
|
|
145
|
+
meta_instrument["antenna"] = {"length": 8.7}
|
|
146
|
+
if platform == "ALOS2":
|
|
147
|
+
meta_instrument["antenna"] = {"length": 9.9}
|
|
148
|
+
|
|
149
|
+
if "pulse" in iii:
|
|
150
|
+
meta_instrument["pulse"] = iii.pop("pulse")
|
|
151
|
+
|
|
152
|
+
return meta_instrument
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def refsys_substructure(iii):
|
|
156
|
+
src_utc = np.datetime64(iii["ytime"], "ns")
|
|
157
|
+
# truncate to previous whole second boundary
|
|
158
|
+
yt_ref = np.datetime64(src_utc, "s")
|
|
159
|
+
# The tag 'orbit' was replaced by 'trajectory' after a short while
|
|
160
|
+
if "orbit" in iii:
|
|
161
|
+
iii["trajectory"] = iii["orbit"]
|
|
162
|
+
del iii["orbit"]
|
|
163
|
+
leftlook = iii["leftlooking"] if "leftlooking" in iii else 0
|
|
164
|
+
lookdir = "right" if leftlook == 0 else "left"
|
|
165
|
+
return make_refsys(
|
|
166
|
+
{
|
|
167
|
+
"type": "sar_zd_sr",
|
|
168
|
+
"utc": yt_ref,
|
|
169
|
+
"lookdirection": lookdir,
|
|
170
|
+
"trajectory": iii["trajectory"],
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def is_ytime(key):
|
|
176
|
+
# print("is_ytime: looking at {}".format(key))
|
|
177
|
+
return key in ["ytime", "mastergeometry"]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
conversions = ((is_ytime, gtime.parse_iso8601),)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def meta_from_info(info, refgrid=None, nodatavalue=None):
|
|
184
|
+
"""Convert a gdar *info* dictionary into a full metadata tree with grid.
|
|
185
|
+
|
|
186
|
+
Translates legacy info fields (trajectory, xtime, doppler, srgr, …) into
|
|
187
|
+
the canonical metadata structure expected by ``make_meta`` / ``make_grid``.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
info : dict or Immutable
|
|
192
|
+
Raw metadata dictionary as read from a ``.info`` / ``.json`` file.
|
|
193
|
+
refgrid : Grid or None
|
|
194
|
+
If provided, the output grid is co-registered to this reference.
|
|
195
|
+
nodatavalue : scalar or None
|
|
196
|
+
Override for the no-data sentinel; inferred from dtype if *None*.
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
dict
|
|
201
|
+
Metadata tree ready for ``make_meta()``.
|
|
202
|
+
"""
|
|
203
|
+
if isinstance(info, base.Immutable):
|
|
204
|
+
iii = info[...]
|
|
205
|
+
else:
|
|
206
|
+
# Shallow copy, this means only nodes contained in the
|
|
207
|
+
# root can be deleted from 'iii' without changing 'info'
|
|
208
|
+
iii = copy.copy(info)
|
|
209
|
+
|
|
210
|
+
_meta = {}
|
|
211
|
+
_meta["format"] = iii["format"]
|
|
212
|
+
_meta["description"] = iii["description"] if "description" in iii else iii["format"]
|
|
213
|
+
|
|
214
|
+
# Various ways of describing data types, translate to numpy dtype
|
|
215
|
+
if "datatemplate" in iii:
|
|
216
|
+
_meta["dtype"] = base.dtype_from_dtemplate(iii["datatemplate"])
|
|
217
|
+
|
|
218
|
+
del iii["datatemplate"]
|
|
219
|
+
del iii["datatype"]
|
|
220
|
+
elif "datatype" in iii:
|
|
221
|
+
_meta["dtype"] = np.dtype(IDL_type_map[iii["datatype"]])
|
|
222
|
+
del iii["datatype"]
|
|
223
|
+
else:
|
|
224
|
+
raise ValueError("No type information found in info")
|
|
225
|
+
|
|
226
|
+
assert "dtype" in _meta, "dtype missing in meta: 87tguIBKJInqhVJQCms"
|
|
227
|
+
|
|
228
|
+
_meta["nodatavalue"] = value_from_dtype(_meta["dtype"], value=nodatavalue)
|
|
229
|
+
|
|
230
|
+
# The tag 'orbit' was replaced by 'trajectory' after a short while
|
|
231
|
+
if "orbit" in iii:
|
|
232
|
+
iii["trajectory"] = iii["orbit"]
|
|
233
|
+
del iii["orbit"]
|
|
234
|
+
|
|
235
|
+
if "trajectory" in iii and "xtime" in iii:
|
|
236
|
+
if "srgr" in iii:
|
|
237
|
+
info_type = "sar_zd_gr"
|
|
238
|
+
elif "gpri" in info:
|
|
239
|
+
info_type = "gbradar"
|
|
240
|
+
else:
|
|
241
|
+
info_type = "sar_zd_sr"
|
|
242
|
+
else:
|
|
243
|
+
info_type = ""
|
|
244
|
+
leftlook = iii["leftlooking"] if "leftlooking" in iii else 0
|
|
245
|
+
lookdir = "right" if leftlook == 0 else "left"
|
|
246
|
+
# Grid:
|
|
247
|
+
inp0 = None
|
|
248
|
+
inp1 = None
|
|
249
|
+
if info_type in ["sar_zd_sr", "gbradar"]:
|
|
250
|
+
# for InSAR, the product name is in the input_0
|
|
251
|
+
# and input_1 substructures.
|
|
252
|
+
src_utc = np.datetime64(iii["ytime"], "ns")
|
|
253
|
+
# truncate to previous whole second boundary
|
|
254
|
+
yt_ref = np.datetime64(src_utc, "s")
|
|
255
|
+
yt_orig = (src_utc - yt_ref) / gtime.sec
|
|
256
|
+
|
|
257
|
+
_ref = {
|
|
258
|
+
"type": "sar_zd_sr",
|
|
259
|
+
"utc": yt_ref,
|
|
260
|
+
"lookdirection": lookdir,
|
|
261
|
+
"trajectory": iii["trajectory"],
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if "input_0" in iii:
|
|
265
|
+
_ref["ref_0"] = refsys_substructure(iii["input_0"])
|
|
266
|
+
inp0 = iii.pop("input_0")
|
|
267
|
+
if "input_1" in iii:
|
|
268
|
+
_ref["ref_1"] = refsys_substructure(iii["input_1"])
|
|
269
|
+
inp1 = iii.pop("input_1")
|
|
270
|
+
my_ref = make_refsys(_ref)
|
|
271
|
+
|
|
272
|
+
# for coreg data, the grid must be taken from the reference geometry
|
|
273
|
+
# and the relative orbit defines the alternate refsys 'ref_0'
|
|
274
|
+
if refgrid is not None:
|
|
275
|
+
grid = refgrid[...]
|
|
276
|
+
# grid['ref_0'] = my_ref
|
|
277
|
+
refs = grid["refsys"][...]
|
|
278
|
+
refs["original"] = my_ref
|
|
279
|
+
grid["refsys"] = refs
|
|
280
|
+
else:
|
|
281
|
+
grid = {
|
|
282
|
+
# TODO: Check with orbit's t_ref
|
|
283
|
+
"origin": np.array([yt_orig, iii["xtime"]]),
|
|
284
|
+
"shape": np.array([iii["ysize"], iii["xsize"]]),
|
|
285
|
+
"samplespacing": np.array([1.0 / iii["ysamplefreq"], 1.0 / iii["xsamplefreq"]]),
|
|
286
|
+
"refsys": my_ref,
|
|
287
|
+
}
|
|
288
|
+
_meta["grid"] = grid
|
|
289
|
+
# Only keeping doppler from input0??
|
|
290
|
+
if (
|
|
291
|
+
("doppler" in iii) or (inp0 is not None and "doppler" in inp0)
|
|
292
|
+
) and info_type == "sar_zd_sr":
|
|
293
|
+
curdop = iii["doppler"] if ("doppler" in iii) else inp0["doppler"]
|
|
294
|
+
if "ytime" in curdop:
|
|
295
|
+
dopytime = curdop["ytime"]
|
|
296
|
+
dopval = curdop["offset"]
|
|
297
|
+
else:
|
|
298
|
+
dopytime = [yt_ref, yt_ref + np.timedelta64(1, "s")]
|
|
299
|
+
dopval = np.repeat(curdop["offset"][np.newaxis, :], 2, axis=0)
|
|
300
|
+
dopyarr = np.array(dopytime, "M8[ns]")
|
|
301
|
+
if not dopyarr.shape:
|
|
302
|
+
# Doppler time is scalar, make array with two elements
|
|
303
|
+
dopyarr = np.asarray(
|
|
304
|
+
[
|
|
305
|
+
np.datetime64(dopytime, "[ns]"),
|
|
306
|
+
np.datetime64(dopytime, "[ns]") + np.timedelta64(1, "s"),
|
|
307
|
+
]
|
|
308
|
+
)
|
|
309
|
+
dopval = np.repeat(curdop["offset"][np.newaxis, :], 2, axis=0)
|
|
310
|
+
dop = {
|
|
311
|
+
"rgtime": curdop["xtime"],
|
|
312
|
+
"utc": dopyarr,
|
|
313
|
+
"values": dopval,
|
|
314
|
+
}
|
|
315
|
+
_meta["doppler"] = {"centroid": dop}
|
|
316
|
+
if "doppler" in iii:
|
|
317
|
+
del iii["doppler"]
|
|
318
|
+
|
|
319
|
+
del iii["xtime"]
|
|
320
|
+
del iii["ytime"]
|
|
321
|
+
del iii["xsamplefreq"]
|
|
322
|
+
del iii["ysamplefreq"]
|
|
323
|
+
del iii["statevector"]
|
|
324
|
+
del iii["trajectory"]
|
|
325
|
+
|
|
326
|
+
# For InSAR products, preserve original refsys's
|
|
327
|
+
for orig_i in range(2):
|
|
328
|
+
subkey = "input_{}".format(orig_i)
|
|
329
|
+
subref = "ref_{}".format(orig_i)
|
|
330
|
+
if subkey in iii:
|
|
331
|
+
m0 = meta_from_info(iii[subkey])
|
|
332
|
+
del iii[subkey]
|
|
333
|
+
_meta["grid"][subref] = m0.grid.refsys
|
|
334
|
+
# Delete grid/refsys from substructure
|
|
335
|
+
mm = m0[..., ...]
|
|
336
|
+
del mm["grid"]
|
|
337
|
+
_meta[subkey] = base.immutable(mm)
|
|
338
|
+
|
|
339
|
+
elif info_type == "sar_zd_gr":
|
|
340
|
+
# Ground range products, need a slant range refsys
|
|
341
|
+
# but different accessors
|
|
342
|
+
|
|
343
|
+
# TODO: Unify with sar_zd_sr, above
|
|
344
|
+
|
|
345
|
+
gr_orig = 0 # How to detect when gr origin is not zero?
|
|
346
|
+
|
|
347
|
+
if isinstance(iii["srgr"], list) or isinstance(iii["srgr"], np.ndarray):
|
|
348
|
+
groff = iii["srgr"][0]["offset"][0]
|
|
349
|
+
aztime = iii["srgr"]["ytime"]
|
|
350
|
+
grsr = iii["srgr"]["srgr_coeff"]
|
|
351
|
+
gr0 = iii["srgr"]["gr0"]
|
|
352
|
+
else:
|
|
353
|
+
groff = iii["srgr"]["offset"][0]
|
|
354
|
+
sft = np.asarray([-3, 3]) * gtime.sec
|
|
355
|
+
aztime = np.asarray(np.datetime64(iii["srgr"]["ytime"]) + sft).astype("datetime64[ns]")
|
|
356
|
+
grsr = np.row_stack((iii["srgr"]["srgr_coeff"], iii["srgr"]["srgr_coeff"]))
|
|
357
|
+
gr0 = np.repeat(iii["srgr"]["gr0"], 2)
|
|
358
|
+
# truncate to previous whole second boundary
|
|
359
|
+
utc_ref = np.min(aztime).astype("datetime64[s]").astype("datetime64[ns]")
|
|
360
|
+
my_srref = make_refsys(
|
|
361
|
+
{
|
|
362
|
+
"type": "sar_zd_sr",
|
|
363
|
+
"utc": utc_ref,
|
|
364
|
+
"lookdirection": lookdir,
|
|
365
|
+
"trajectory": iii["trajectory"],
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# assert abs(groff - round(groff)) < 1e-4, 'noninteger offset'
|
|
370
|
+
# GSAR doesn't have 'origin', so 'srgr.offset' has
|
|
371
|
+
# taken some of that role for ground range refsys
|
|
372
|
+
# srgr.offset is in units of pixels, refsys.origin in refsys coordinates
|
|
373
|
+
# need samplespacing to fix this:
|
|
374
|
+
ssp = np.array([1.0 / iii["ysamplefreq"], iii["xspacing"]])
|
|
375
|
+
src_utc = np.datetime64(iii["ytime"], "ns")
|
|
376
|
+
coo_orig = np.array([(src_utc - utc_ref) / gtime.sec, gr_orig + groff * ssp[1]])
|
|
377
|
+
|
|
378
|
+
grspace = iii["xspacing"]
|
|
379
|
+
gr_max = grspace * iii["xsize"]
|
|
380
|
+
|
|
381
|
+
# Assume gr->sr polynomials are valid 50 km outside the product in
|
|
382
|
+
# either direction.
|
|
383
|
+
# Necessary for geocoding, at least until interpolators are NaN-tolerant
|
|
384
|
+
# Need to limit somewhat to avoid going outside valid areas for cooefficients.
|
|
385
|
+
grbd = np.min([55000.0, gr_max])
|
|
386
|
+
|
|
387
|
+
range_mapping = {
|
|
388
|
+
"utc": aztime,
|
|
389
|
+
"gr0": gr0,
|
|
390
|
+
"tol": np.array([1e-5]),
|
|
391
|
+
"grsr_coeff": grsr, # in GSAR, 'srgr' maps from ground to slant range
|
|
392
|
+
}
|
|
393
|
+
# In gdar, as in Sentinel-1, the opposite is true
|
|
394
|
+
|
|
395
|
+
# Possible to do sanity check here :
|
|
396
|
+
# assert polyval(grsr_coeff, 0-gr0) == iii['srgr']['xtime']*const.c/2
|
|
397
|
+
|
|
398
|
+
my_ref = make_refsys(
|
|
399
|
+
{
|
|
400
|
+
"type": "sar_zd_gr",
|
|
401
|
+
"utc": utc_ref,
|
|
402
|
+
"range_mapping": range_mapping,
|
|
403
|
+
"grlim": np.array([-grbd, gr_max + grbd]) + coo_orig[1],
|
|
404
|
+
"sr_ref": my_srref,
|
|
405
|
+
}
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
# The GR grid is in units of [azimuth seconds, ground range metres]
|
|
409
|
+
_meta["grid"] = {
|
|
410
|
+
"origin": coo_orig,
|
|
411
|
+
"shape": np.array([iii["ysize"], iii["xsize"]]),
|
|
412
|
+
"samplespacing": ssp,
|
|
413
|
+
"offset": np.array([0, 0], dtype=np.int64),
|
|
414
|
+
"refsys": my_ref,
|
|
415
|
+
}
|
|
416
|
+
""" No doppler for grd products?
|
|
417
|
+
if 'doppler' in iii and 'ytime' in iii['doppler']:
|
|
418
|
+
dop = {
|
|
419
|
+
'rgtime': iii['doppler']['xtime'],
|
|
420
|
+
'utc': np.array(iii['doppler']['ytime'], 'M8[ns]'),
|
|
421
|
+
'values': iii['doppler']['offset'],
|
|
422
|
+
}
|
|
423
|
+
_meta['doppler'] = {'centroid': dop}
|
|
424
|
+
del iii['doppler']
|
|
425
|
+
"""
|
|
426
|
+
del iii["xtime"]
|
|
427
|
+
del iii["ytime"]
|
|
428
|
+
del iii["xsamplefreq"]
|
|
429
|
+
del iii["ysamplefreq"]
|
|
430
|
+
del iii["xspacing"]
|
|
431
|
+
del iii["yspacing"]
|
|
432
|
+
del iii["statevector"]
|
|
433
|
+
del iii["trajectory"]
|
|
434
|
+
del iii["srgr"]
|
|
435
|
+
|
|
436
|
+
else:
|
|
437
|
+
_meta["grid"] = {
|
|
438
|
+
"origin": np.array([0, 0]),
|
|
439
|
+
"shape": np.array([iii["ysize"], iii["xsize"]]),
|
|
440
|
+
"samplespacing": np.array([1, 1]),
|
|
441
|
+
"refsys": {"type": ""},
|
|
442
|
+
}
|
|
443
|
+
del iii["xsize"]
|
|
444
|
+
del iii["ysize"]
|
|
445
|
+
del iii["format"]
|
|
446
|
+
del iii["nchannels"]
|
|
447
|
+
del iii["endian"]
|
|
448
|
+
|
|
449
|
+
# Instrument:
|
|
450
|
+
if info_type in ["sar_zd_sr", "sar_zd_gr", "gbradar"]:
|
|
451
|
+
if inp0 is not None:
|
|
452
|
+
void = _instrument_substructure(iii)
|
|
453
|
+
_meta["instrument"] = _instrument_substructure(inp0)
|
|
454
|
+
elif inp1 is not None:
|
|
455
|
+
void = _instrument_substructure(iii)
|
|
456
|
+
_meta["instrument"] = _instrument_substructure(inp1)
|
|
457
|
+
else:
|
|
458
|
+
_meta["instrument"] = _instrument_substructure(iii)
|
|
459
|
+
|
|
460
|
+
if info_type in ["sar_zd_sr"]:
|
|
461
|
+
if "azsweeprate" in _meta["instrument"]:
|
|
462
|
+
if _meta["instrument"]["azsweeprate"] != 0:
|
|
463
|
+
raise ValueError("Need to subtract Sweep from Doppler Centroid RIGHT NOW!")
|
|
464
|
+
|
|
465
|
+
if ("gate" in iii) or (inp0 is not None and "gate" in inp0):
|
|
466
|
+
_gate = _reform_gate(iii.pop("gate") if "gate" in iii else inp0["gate"], my_ref["utc"])
|
|
467
|
+
try:
|
|
468
|
+
igate = dict(_gate)
|
|
469
|
+
except ValueError:
|
|
470
|
+
igate = {}
|
|
471
|
+
for ik in _gate.dtype.names:
|
|
472
|
+
igate[ik] = _gate[ik]
|
|
473
|
+
_meta["gate"] = igate
|
|
474
|
+
procdicts = {}
|
|
475
|
+
for bwkey, winkey, metakey in zip(
|
|
476
|
+
["ybandwidth", "xbandwidth"],
|
|
477
|
+
["ywindowfunc", "xwindowfunc"],
|
|
478
|
+
["azimuth", "range"],
|
|
479
|
+
):
|
|
480
|
+
if bwkey in iii or winkey in iii:
|
|
481
|
+
pmeta = {}
|
|
482
|
+
if _meta["format"] == "SLC":
|
|
483
|
+
pmeta["numberoflooks"] = 1 # What to do for non-SLCs?
|
|
484
|
+
if bwkey in iii:
|
|
485
|
+
pmeta["totalbandwidth"] = iii.pop(bwkey)
|
|
486
|
+
if winkey in iii:
|
|
487
|
+
win = iii.pop(winkey)
|
|
488
|
+
if win.lower().startswith("hanning"):
|
|
489
|
+
pmeta["windowtype"] = "general_hamming"
|
|
490
|
+
if len(win.lower().split(" ")) > 1:
|
|
491
|
+
# assumes format 'HANNING (0.90)'
|
|
492
|
+
pmeta["windowparameters"] = float(win.lower().split(" ")[1][1:-1])
|
|
493
|
+
else:
|
|
494
|
+
pmeta["windowtype"] = win.lower()
|
|
495
|
+
procdicts[metakey] = pmeta
|
|
496
|
+
if len(procdicts) == 2:
|
|
497
|
+
add_slc_processing_to_meta(_meta, procdicts["azimuth"], procdicts["range"])
|
|
498
|
+
|
|
499
|
+
for ifgtag in ["dt", "baseline", "nlooks"]:
|
|
500
|
+
if ifgtag in iii:
|
|
501
|
+
if "interferogram" not in _meta:
|
|
502
|
+
_meta["interferogram"] = {}
|
|
503
|
+
if ifgtag == "nlooks":
|
|
504
|
+
_meta["interferogram"][ifgtag] = iii.pop(ifgtag)[::-1]
|
|
505
|
+
else:
|
|
506
|
+
_meta["interferogram"][ifgtag] = iii.pop(ifgtag)
|
|
507
|
+
|
|
508
|
+
_meta["info_leftovers"] = {}
|
|
509
|
+
for kk in iii:
|
|
510
|
+
if kk == "geometricdoppler" or kk == "attitude":
|
|
511
|
+
idict = iii[kk].copy()
|
|
512
|
+
idict["ytime"] = np.asarray([gtime.parse_iso8601(iteri) for iteri in idict["ytime"]])
|
|
513
|
+
_meta["info_leftovers"][kk] = idict
|
|
514
|
+
else:
|
|
515
|
+
_meta["info_leftovers"][kk] = iii[kk]
|
|
516
|
+
|
|
517
|
+
if inp0 is not None:
|
|
518
|
+
for kk in [
|
|
519
|
+
"procfacility",
|
|
520
|
+
"procsoftware",
|
|
521
|
+
"calib",
|
|
522
|
+
"xwindowfunc",
|
|
523
|
+
"ywindowfunc",
|
|
524
|
+
"geometricdoppler",
|
|
525
|
+
"attitude",
|
|
526
|
+
"mastergeometry",
|
|
527
|
+
]:
|
|
528
|
+
if kk in inp0:
|
|
529
|
+
if kk == "geometricdoppler" or kk == "attitude":
|
|
530
|
+
inp0[kk]["ytime"] = np.asarray(
|
|
531
|
+
[gtime.parse_iso8601(iteri) for iteri in inp0[kk]["ytime"]]
|
|
532
|
+
)
|
|
533
|
+
_meta["info_leftovers"][kk] = inp0[kk]
|
|
534
|
+
|
|
535
|
+
for kk in ["xbandwidth", "ybandwidth"]:
|
|
536
|
+
if inp1 is not None:
|
|
537
|
+
val = min([inp0[kk], inp1[kk]])
|
|
538
|
+
else:
|
|
539
|
+
val = inp0[kk]
|
|
540
|
+
_meta["info_leftovers"][kk] = val
|
|
541
|
+
|
|
542
|
+
mm = make_meta(_meta, conversions=conversions)
|
|
543
|
+
# keyboard()
|
|
544
|
+
return mm
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _reform_gate(_gate, utc_ref):
|
|
548
|
+
newgate = {}
|
|
549
|
+
newgate["shape"] = np.asarray([_gate["ysize"], _gate["xsize"]]).astype(np.int32)
|
|
550
|
+
newgate["samplespacing"] = np.asarray([1 / _gate["ysamplefreq"], 1 / _gate["xsamplefreq"]])
|
|
551
|
+
y0 = (gtime.parse_iso8601(_gate["ytime"]) - utc_ref) / gtime.sec
|
|
552
|
+
newgate["origin"] = np.asarray([y0, _gate["xtime"]])
|
|
553
|
+
newgate["offset"] = np.zeros(2)
|
|
554
|
+
return newgate
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
class Struct:
|
|
558
|
+
"""This class is used for its members, not its methods.
|
|
559
|
+
|
|
560
|
+
The primary convenience lies in saying foo.bar instead of foo['bar'].
|
|
561
|
+
In addition, some automatic translation is done during instantiation,
|
|
562
|
+
e.g. timestamps into datetime64 objects, and datatype specifications.
|
|
563
|
+
"""
|
|
564
|
+
|
|
565
|
+
def __init__(self, d=None):
|
|
566
|
+
if d is None:
|
|
567
|
+
return
|
|
568
|
+
|
|
569
|
+
for k in d:
|
|
570
|
+
v = d[k]
|
|
571
|
+
# print("k: {}, v: {}".format(k, v))
|
|
572
|
+
if k.lower() == "datatype":
|
|
573
|
+
if isinstance(v, int):
|
|
574
|
+
v = IDL_type_map[v]
|
|
575
|
+
elif type(v) is list:
|
|
576
|
+
if type(v[0]) is dict:
|
|
577
|
+
# v = DataFrame(v)
|
|
578
|
+
# Check for simple special case [{'re': xx, 'im': yy}, ...]
|
|
579
|
+
if set(v[0].keys()) == set(["re", "im"]):
|
|
580
|
+
v = np.array(v.re.values + 1j * v.im.values)
|
|
581
|
+
elif type(v) is dict:
|
|
582
|
+
v = Struct(v)
|
|
583
|
+
# elif type(v) in [unicode, str]:
|
|
584
|
+
elif type(v) in [str]:
|
|
585
|
+
try:
|
|
586
|
+
v = np.datetime64(v)
|
|
587
|
+
except ValueError:
|
|
588
|
+
pass
|
|
589
|
+
setattr(self, k.lower(), v)
|
|
590
|
+
|
|
591
|
+
# figure out dtype from datatype/datatemplate later
|
|
592
|
+
# must co
|
|
593
|
+
# if hasattr(self, 'datatemplate'):
|
|
594
|
+
# self.dtype = dtype_from_dtemplate(self.datatemplate.lower())
|
|
595
|
+
# elif hasattr(self, 'datatype'):
|
|
596
|
+
# self.datatype = np.dtype(IDL_type_map[self.datatype])
|
|
597
|
+
|
|
598
|
+
# Support iteration over keys and values, deferring to underlying dict
|
|
599
|
+
def __iter__(self):
|
|
600
|
+
return iter(self.__dict__)
|
|
601
|
+
|
|
602
|
+
def __setitem__(self, key, val):
|
|
603
|
+
# print("setting {0} to {1} in {2}".format(key, val, self))
|
|
604
|
+
setattr(self, key, val)
|
|
605
|
+
|
|
606
|
+
def __getitem__(self, key):
|
|
607
|
+
return getattr(self, key)
|
|
608
|
+
|
|
609
|
+
def set(self, **kw):
|
|
610
|
+
for k in kw:
|
|
611
|
+
self[k] = kw[k]
|
|
612
|
+
|
|
613
|
+
def copy(self):
|
|
614
|
+
return Struct(self)
|
|
615
|
+
|
|
616
|
+
def __repr__(self, level=4):
|
|
617
|
+
d = self.__dict__
|
|
618
|
+
return "%s(%s)" % (
|
|
619
|
+
self.__class__.__name__,
|
|
620
|
+
(",\n" + " " * level).join(
|
|
621
|
+
"%s=%s" % (k, (d[k].__repr__(level + 4) if isinstance(d[k], Struct) else d[k]))
|
|
622
|
+
for k in d
|
|
623
|
+
),
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
def tohash(self):
|
|
627
|
+
h = {}
|
|
628
|
+
for k in self.__dict__:
|
|
629
|
+
v = self.__dict__[k]
|
|
630
|
+
if k == "datatype":
|
|
631
|
+
try:
|
|
632
|
+
h[k] = IDL_type_map.index(v)
|
|
633
|
+
continue
|
|
634
|
+
except ValueError:
|
|
635
|
+
# structured types, parse them here
|
|
636
|
+
# print("datatype missing")
|
|
637
|
+
# keyboard()
|
|
638
|
+
pass
|
|
639
|
+
elif isinstance(v, Struct):
|
|
640
|
+
h[k] = v.tohash()
|
|
641
|
+
continue
|
|
642
|
+
elif isinstance(v, np.datetime64):
|
|
643
|
+
h[k] = str(v)
|
|
644
|
+
continue
|
|
645
|
+
elif isinstance(v, np.ndarray):
|
|
646
|
+
if np.iscomplexobj(v):
|
|
647
|
+
h[k] = [{"re": x.real, "im": x.imag} for x in v]
|
|
648
|
+
continue
|
|
649
|
+
if len(v.dtype) == 0:
|
|
650
|
+
h[k] = [str(x) for x in v]
|
|
651
|
+
continue
|
|
652
|
+
elif isinstance(v, DataFrame):
|
|
653
|
+
print(k + ": DataFrame")
|
|
654
|
+
keyboard()
|
|
655
|
+
else:
|
|
656
|
+
h[k] = v
|
|
657
|
+
return h
|