|
1 | 1 | import datetime |
2 | 2 | import pytest |
| 3 | + |
3 | 4 | import numpy as np |
4 | 5 |
|
5 | | -from RAiDER.losreader import Raytracing |
| 6 | +from pyproj import CRS |
| 7 | +from scipy.interpolate import RegularGridInterpolator as rgi |
| 8 | + |
| 9 | +from RAiDER.delay import _build_cube_ray |
| 10 | +from RAiDER.models.weatherModel import ( |
| 11 | + WeatherModel, |
| 12 | +) |
| 13 | + |
| 14 | +_LON0 = 0 |
| 15 | +_LAT0 = 0 |
| 16 | +_OMEGA = 0.1 / (180/np.pi) |
| 17 | + |
| 18 | +class MockWeatherModel(WeatherModel): |
| 19 | + """Implement abstract methods for testing.""" |
| 20 | + |
| 21 | + def __init__(self): |
| 22 | + super().__init__() |
| 23 | + |
| 24 | + self._k1 = 1 |
| 25 | + self._k2 = 1 |
| 26 | + self._k3 = 1 |
| 27 | + |
| 28 | + self._Name = "MOCK" |
| 29 | + self._valid_range = (datetime.datetime(1970, 1, 1), "Present") |
| 30 | + self._lag_time = datetime.timedelta(days=15) |
| 31 | + |
| 32 | + def _fetch(self, ll_bounds, time, out): |
| 33 | + pass |
| 34 | + |
| 35 | + def load_weather(self, *args, **kwargs): |
| 36 | + _N_Z = 32 |
| 37 | + self._ys = np.arange(-2,3) + _LAT0 |
| 38 | + self._xs = np.arange(-3,4) + _LON0 |
| 39 | + self._zs = np.linspace(0, 1e5, _N_Z) |
| 40 | + self._t = np.ones((len(self._ys), len(self._xs), _N_Z)) |
| 41 | + self._e = self._t.copy() |
| 42 | + self._e[:,3:,:] = 2 |
| 43 | + |
| 44 | + _p = np.arange(31, -1, -1) |
| 45 | + self._p = np.broadcast_to(_p, self._t.shape) |
| 46 | + |
| 47 | + self._true_hydro_refr = np.broadcast_to(_p, (self._t.shape)) |
| 48 | + self._true_wet_ztd = 1e-6 * 2 * np.broadcast_to(np.flip(self._zs), (self._t.shape)) |
| 49 | + self._true_wet_ztd[:,3:] = 2 * self._true_wet_ztd[:,3:] |
| 50 | + |
| 51 | + self._true_hydro_ztd = np.zeros(self._t.shape) |
| 52 | + for layer in range(len(self._zs)): |
| 53 | + self._true_hydro_ztd[:,:,layer] = 1e-6 * 0.5 * (self._zs[-1] - self._zs[layer]) * _p[layer] |
| 54 | + |
| 55 | + self._true_wet_refr = 2 * np.ones(self._t.shape) |
| 56 | + self._true_wet_refr[:,3:] = 4 |
| 57 | + |
| 58 | + def interpWet(self): |
| 59 | + _ifWet = rgi((self._ys, self._xs, self._zs), self._true_wet_refr) |
| 60 | + return _ifWet |
| 61 | + def interpHydro(self): |
| 62 | + _ifHydro = rgi((self._ys, self._xs, self._zs), self._true_hydro_refr) |
| 63 | + return _ifHydro |
| 64 | + |
| 65 | + |
| 66 | +@pytest.fixture |
| 67 | +def model(): |
| 68 | + return MockWeatherModel() |
| 69 | + |
| 70 | + |
| 71 | +@pytest.fixture |
| 72 | +def setup_fake_raytracing(): |
| 73 | + '''This sets up a fake orbit for the weather model''' |
| 74 | + |
| 75 | + import isce3.ext.isce3 as isce |
| 76 | + from isce3.core import DateTime, TimeDelta |
| 77 | + |
| 78 | + lat0 = _LAT0 # degrees |
| 79 | + lon0 = _LON0 |
| 80 | + hsat = 700000. |
| 81 | + omega = _OMEGA # degrees |
| 82 | + Nvec = 30 |
| 83 | + |
| 84 | + t0 = DateTime("2017-02-12T01:12:30.0") |
| 85 | + |
| 86 | + elp = isce.core.Ellipsoid(6378137.,.0066943799901) |
| 87 | + look = isce.core.LookSide.Left |
| 88 | + |
| 89 | + sat_hgt = elp.a + hsat |
| 90 | + sat_lat = np.sin(np.radians(lat0)) |
| 91 | + clat = np.cos(np.radians(lat0)) |
| 92 | + |
| 93 | + svs = [] |
| 94 | + for k in range(Nvec): |
| 95 | + dt = TimeDelta(100 * k) |
| 96 | + lon = lon0 + omega * dt.total_seconds() |
| 97 | + |
| 98 | + pos = [] |
| 99 | + pos.append(sat_hgt * clat * np.cos(np.radians(lon))) |
| 100 | + pos.append(sat_hgt * clat * np.sin(np.radians(lon))) |
| 101 | + pos.append(sat_hgt * sat_lat) |
| 102 | + |
| 103 | + vel = [] |
| 104 | + vel.append(-omega * pos[1]) |
| 105 | + vel.append(omega * pos[0]) |
| 106 | + vel.append(0.) |
| 107 | + |
| 108 | + epoch = t0 + dt |
| 109 | + |
| 110 | + svs.append( |
| 111 | + isce.core.StateVector(epoch,pos, vel) |
| 112 | + ) |
| 113 | + |
| 114 | + orb = isce.core.Orbit(svs) |
| 115 | + |
| 116 | + return orb, look, elp, sat_hgt |
6 | 117 |
|
| 118 | +def solve(R, hsat, ellipsoid, side='left'): |
| 119 | + # temp = 1.0 + hsat/ellipsoid.a |
| 120 | + # temp1 = R/ellipsoid.a |
| 121 | + # temp2 = R/(ellipsoid.a + hsat) |
| 122 | + t2 = (np.square(hsat) + np.square(R)) - np.square(ellipsoid.a) |
| 123 | + # cosang = 0.5 * (temp + (1.0/temp) - temp1 * temp2) |
| 124 | + cosang = 0.5 * t2 / (R * hsat) |
| 125 | + angdiff = np.arccos(cosang) |
| 126 | + if side=='left': |
| 127 | + x = _LAT0 + angdiff |
| 128 | + else: |
| 129 | + x = _LAT0 - angdiff |
| 130 | + return x |
7 | 131 |
|
8 | | -def test_Raytracing(): |
9 | | - lats = np.array([-90, 0, 0, 90]) |
10 | | - lons = np.array([-90, 0, 90, 180]) |
11 | | - hgts = np.array([-10, 0, 10, 1000]) |
12 | 132 |
|
13 | | - unit_vecs = np.array([[0,0,-1], [1,0,0], [0,1,0], [0,0,1]]) |
| 133 | +@pytest.mark.isce3 |
| 134 | +def test_llhs(setup_fake_raytracing, model): |
| 135 | + orb, look_dir, elp, sat_hgt = setup_fake_raytracing |
| 136 | + llhs = [] |
| 137 | + for k in range(20): |
| 138 | + tinp = 5 + k * 2 |
| 139 | + rng = 800000 + 1000 * k |
| 140 | + expLon = _LON0 + _OMEGA * tinp |
| 141 | + geocentricLat = solve(rng, sat_hgt, elp) |
14 | 142 |
|
15 | | - z = Raytracing() |
16 | | - with pytest.raises(RuntimeError): |
17 | | - z.setPoints(lats=None) |
| 143 | + xyz = [ |
| 144 | + elp.a * np.cos(geocentricLat) * np.cos(expLon), |
| 145 | + elp.a * np.cos(geocentricLat) * np.sin(expLon), |
| 146 | + elp.a * np.sin(geocentricLat) |
| 147 | + ] |
| 148 | + llh = elp.xyz_to_lon_lat(xyz) |
| 149 | + llhs.append(llh) |
18 | 150 |
|
19 | | - z.setPoints(lats=lats, lons=lons, heights = hgts) |
20 | | - assert z._lats.shape == (4,) |
21 | | - assert z._lats.shape == z._lons.shape |
22 | | - assert np.allclose(z._heights, hgts) |
| 151 | + assert len(llhs) == 20 |
23 | 152 |
|
| 153 | +@pytest.mark.skip |
| 154 | +@pytest.mark.isce3 |
| 155 | +def test_build_cube_ray(setup_fake_raytracing, model): |
| 156 | + import isce3.ext.isce3 as isce |
| 157 | + from RAiDER.losreader import state_to_los |
24 | 158 |
|
25 | | -def test_toa(): |
26 | | - lats = np.array([0, 0, 0, 0]) |
27 | | - lons = np.array([0, 180, 90, -90]) |
28 | | - hgts = np.array([0, 0, 0, 0]) |
| 159 | + orb, look_dir, elp, _ = setup_fake_raytracing |
| 160 | + m = model |
| 161 | + m.load_weather() |
29 | 162 |
|
30 | | - z = Raytracing() |
31 | | - z.setPoints(lats=lats, lons=lons, heights=hgts) |
| 163 | + ys = np.arange(-1,1) + _LAT0 |
| 164 | + xs = np.arange(-1,1) + _LON0 |
| 165 | + zs = np.arange(0, 1e5, 1e3) |
32 | 166 |
|
33 | | - # Mock xyz |
34 | | - z._xyz = np.array([[6378137.0, 0.0, 0.0], |
35 | | - [-6378137.0, 0.0, 0.0], |
36 | | - [0.0, 6378137.0, 0.0], |
37 | | - [0.0, -6378137.0, 0.0]]) |
38 | | - z._look_vecs = np.array([[1, 0, 0], |
39 | | - [-1, 0, 0], |
40 | | - [0, 1, 0], |
41 | | - [0, -1, 0]]) |
42 | | - toppts = np.array([[6388137.0, 0.0, 0.0], |
43 | | - [-6388137.0, 0.0, 0.0], |
44 | | - [0.0, 6388137.0, 0.0], |
45 | | - [0.0, -6388137.0, 0.0]]) |
| 167 | + _Y, _X, _Z = np.meshgrid(ys, xs, zs) |
46 | 168 |
|
47 | | - topxyz = z.getIntersectionWithHeight(10000.) |
| 169 | + out_true = np.zeros(_Y.shape) |
| 170 | + t0 = orb.start_time |
| 171 | + tm1 = orb.end_time |
| 172 | + ts = np.arange(t0, tm1 + orb.time.spacing, orb.time.spacing) |
| 173 | + tlist = [orb.reference_epoch + isce.core.TimeDelta(dt) for dt in ts] |
| 174 | + ts = np.broadcast_to(tlist, (1, len(tlist))).T |
| 175 | + svs = np.hstack([ts, orb.position, orb.velocity]) |
48 | 176 |
|
49 | | - assert np.allclose(topxyz, toppts) |
| 177 | + #TODO: Check that the look vectors are not nans |
| 178 | + lv, xyz = state_to_los(svs, np.stack([_Y.ravel(), _X.ravel(), _Z.ravel()], axis=-1),out="ecef") |
| 179 | + out = _build_cube_ray(xs, ys, zs, orb, look_dir, CRS(4326), CRS(4326), [m.interpWet(), m.interpHydro()], elp=elp) |
| 180 | + assert out.shape == out_true.shape |
0 commit comments