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.
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