1
1
import h5py
2
2
import logging
3
3
import numpy as np
4
+ from numpy .testing import assert_allclose
5
+ import os
6
+ import isce3
4
7
from pybind_isce3 .core import LUT2d , DateTime , Orbit , Attitude , EulerAngles
5
8
from pybind_isce3 .product import RadarGridParameters
6
9
from pybind_isce3 .geometry import DEMInterpolator
@@ -21,6 +24,61 @@ def time_units(epoch: DateTime) -> str:
21
24
return "seconds since " + date + " " + time
22
25
23
26
27
+ def assert_same_lut2d_grid (x : np .ndarray , y : np .ndarray , lut : LUT2d ):
28
+ assert_allclose (x [0 ], lut .x_start )
29
+ assert_allclose (y [0 ], lut .y_start )
30
+ assert (len (x ) > 1 ) and (len (y ) > 1 )
31
+ assert_allclose (x [1 ] - x [0 ], lut .x_spacing )
32
+ assert_allclose (y [1 ] - y [0 ], lut .y_spacing )
33
+ assert lut .width == len (x )
34
+ assert lut .length == len (y )
35
+
36
+
37
+ def h5_require_dirname (group : h5py .Group , name : str ):
38
+ """Make sure any intermediate paths in `name` exist in `group`.
39
+ """
40
+ assert os .sep == '/' , "Need to fix HDF5 path manipulation on Windows"
41
+ d = os .path .dirname (name )
42
+ group .require_group (d )
43
+
44
+
45
+ def add_cal_layer (group : h5py .Group , lut : LUT2d , name : str ,
46
+ epoch : DateTime , units : str ):
47
+ """Add calibration LUT to HDF5 group, making sure that its domain matches
48
+ any existing cal LUTs.
49
+
50
+ Parameters
51
+ ----------
52
+ group : h5py.Group
53
+ Group where LUT and its axes will be stored.
54
+ lut : isce3.core.LUT2d
55
+ Look up table. Axes are assumed to be y=zeroDopplerTime, x=slantRange.
56
+ name : str
57
+ Name of dataset to store LUT data (can be path relative to `group`).
58
+ epoch: isce3.core.DateTime
59
+ Reference time associated with y-axis.
60
+ units : str
61
+ Units of lut.data. Will be stored in `units` attribute of dataset.
62
+ """
63
+ # If we've already saved one cal layer then we've already saved its
64
+ # x and y axes. Make sure they're the same and just save the new z data.
65
+ xname , yname = "slantRange" , "zeroDopplerTime"
66
+ if (xname in group ) and (yname in group ):
67
+ x , y = group [xname ], group [yname ]
68
+ assert_same_lut2d_grid (x , y , lut )
69
+ extant_epoch = isce3 .io .get_ref_epoch (y .parent , y .name )
70
+ assert extant_epoch == epoch
71
+ data = lut .data
72
+ z = group .require_dataset (name , data .shape , data .dtype )
73
+ z [...] = data
74
+ elif (xname not in group ) and (yname not in group ):
75
+ h5_require_dirname (group , name )
76
+ lut .save_to_h5 (group , name , epoch , units )
77
+ else :
78
+ raise IOError (f"Found only one of { xname } or { yname } ."
79
+ " Need both or none." )
80
+
81
+
24
82
class SLC (h5py .File ):
25
83
def __init__ (self , * args , band = "LSAR" , product = "RSLC" , ** kw ):
26
84
super ().__init__ (* args , ** kw )
@@ -49,7 +107,7 @@ def set_parameters(self, dop: LUT2d, epoch: DateTime, frequency='A'):
49
107
# Actual LUT goes into a subdirectory, not created by serialization.
50
108
name = f"frequency{ frequency } "
51
109
fg = g .require_group (name )
52
- dop . save_to_h5 ( g , f"{ name } /dopplerCentroid" , epoch , "Hz" )
110
+ add_cal_layer ( g , dop , f"{ name } /dopplerCentroid" , epoch , "Hz" )
53
111
# TODO veff, fmrate not used anywhere afaict except product io.
54
112
v = np .zeros_like (dop .data )
55
113
g .require_dataset ("effectiveVelocity" , v .shape , v .dtype , data = v )
@@ -108,15 +166,14 @@ def swath(self, frequency="A") -> h5py.Group:
108
166
109
167
def add_polarization (self , frequency = "A" , pol = "HH" ):
110
168
assert len (pol ) == 2 and pol [0 ] in "HVLR" and pol [1 ] in "HV"
169
+ pols = np .string_ ([pol ]) # careful not to promote to unicode below
111
170
g = self .swath (frequency )
112
171
name = "listOfPolarizations"
113
172
if name in g :
114
- pols = np .array (g [name ])
115
- assert ( pol not in pols )
116
- pols = np .append (pols , [ pol ] )
173
+ old_pols = np .array (g [name ])
174
+ assert pols [ 0 ] not in old_pols
175
+ pols = np .append (old_pols , pols )
117
176
del g [name ]
118
- else :
119
- pols = np .array ([pol ], dtype = "S2" )
120
177
dset = g .create_dataset (name , data = pols )
121
178
desc = f"List of polarization layers with frequency{ frequency } "
122
179
dset .attrs ["description" ] = np .string_ (desc )
0 commit comments