|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
# vim:fileencoding=utf-8 |
|
3
|
|
|
# |
|
4
|
|
|
# Copyright (c) 2017 Stefan Bender |
|
5
|
|
|
# |
|
6
|
|
|
# This file is part of sciapy. |
|
7
|
|
|
# sciapy is free software: you can redistribute it or modify it |
|
8
|
|
|
# under the terms of the GNU General Public License as published by |
|
9
|
|
|
# the Free Software Foundation, version 2. |
|
10
|
|
|
# See accompanying LICENSE file or http://www.gnu.org/licenses/gpl-2.0.html. |
|
11
|
1 |
|
"""SCIAMACHY level 1c limb spectra hdf5 interface |
|
12
|
|
|
""" |
|
13
|
|
|
|
|
14
|
1 |
|
from __future__ import absolute_import, division, print_function |
|
15
|
|
|
|
|
16
|
1 |
|
import logging |
|
17
|
|
|
|
|
18
|
1 |
|
import numpy as np |
|
19
|
1 |
|
from astropy.time import Time |
|
20
|
|
|
|
|
21
|
1 |
|
from ._types import _limb_data_dtype |
|
22
|
|
|
|
|
23
|
1 |
|
logging.basicConfig(level=logging.INFO, |
|
24
|
|
|
format="[%(levelname)-8s] (%(asctime)s) " |
|
25
|
|
|
"%(filename)s:%(lineno)d %(message)s", |
|
26
|
|
|
datefmt="%Y-%m-%d %H:%M:%S %z") |
|
27
|
|
|
|
|
28
|
1 |
|
def _calc_angles(sza_in, los_in, saa_in, z_in, z_out, earth_radius): |
|
29
|
|
|
"""SCIAMACHY limb scan angle setup |
|
30
|
|
|
|
|
31
|
|
|
Calculates the solar zenith, solar azimuth, and line-of-sight angles |
|
32
|
|
|
to the tangent point (tp), to the top of the atmosphere (toa), |
|
33
|
|
|
and to the satellite (sat). All angles are in degrees. |
|
34
|
|
|
|
|
35
|
|
|
Parameters |
|
36
|
|
|
---------- |
|
37
|
|
|
sza_in : ndarray |
|
38
|
|
|
The solar zenith angles (per tangent point). |
|
39
|
|
|
los_in : ndarray |
|
40
|
|
|
The line-of-sight zenith angles (per tangent point). |
|
41
|
|
|
saa_in : ndarray |
|
42
|
|
|
The relative solar azimuth angles (per tangent point). |
|
43
|
|
|
z_in : ndarray |
|
44
|
|
|
The input altitudes, can be tangent heights, top of |
|
45
|
|
|
atmosphere, or satellite altitudes. |
|
46
|
|
|
z_out : ndarray |
|
47
|
|
|
The output altitude, can be tangent heights, top of |
|
48
|
|
|
atmosphere, or satellite altitudes. |
|
49
|
|
|
earth_radius : ndarray |
|
50
|
|
|
The earth radii (per tangent point). |
|
51
|
|
|
|
|
52
|
|
|
Returns |
|
53
|
|
|
------- |
|
54
|
|
|
sza_out : ndarray |
|
55
|
|
|
The calculated solar zenith angles for the output altitudes. |
|
56
|
|
|
los_out : ndarray |
|
57
|
|
|
The calculated line-of-sight angles for the output altitudes. |
|
58
|
|
|
saa_out : ndarray |
|
59
|
|
|
The calculated solar azimuth angles for the output altitudes. |
|
60
|
|
|
""" |
|
61
|
|
|
def sign(x, y): |
|
62
|
|
|
xa = np.full_like(y, np.abs(x)) |
|
63
|
|
|
xa[np.where(y < 0.)] *= -1 |
|
64
|
|
|
return xa |
|
65
|
|
|
|
|
66
|
|
|
cos_psi_in = np.cos(np.radians(sza_in)) |
|
67
|
|
|
mju_in = np.cos(np.radians(los_in)) |
|
68
|
|
|
cos_phi_0 = np.cos(np.radians(saa_in)) |
|
69
|
|
|
sin_phi_0 = np.sin(np.radians(saa_in)) |
|
70
|
|
|
|
|
71
|
|
|
# /* start original calculation in angles.f */ |
|
72
|
|
|
r = earth_radius + z_in |
|
73
|
|
|
sin_1 = np.sqrt(1.0 - mju_in**2) |
|
74
|
|
|
h_0 = r * (sin_1 - 1.0) + z_in |
|
75
|
|
|
|
|
76
|
|
|
z_out[np.where(z_out < h_0)] = h_0[np.where(z_out < h_0)] |
|
77
|
|
|
|
|
78
|
|
|
delta = (np.sqrt((2.0 * earth_radius + z_in + h_0) * (z_in - h_0)) - |
|
79
|
|
|
np.sqrt((2.0 * earth_radius + z_out + h_0) * (z_out - h_0))) |
|
80
|
|
|
mju_out = ((mju_in * r - delta) / |
|
81
|
|
|
np.sqrt((mju_in * r - delta)**2 + (r * sin_1)**2)) |
|
82
|
|
|
sin_out = r * sin_1 / (earth_radius + z_out) |
|
83
|
|
|
sin_psi = np.sqrt(1.0 - cos_psi_in**2) |
|
84
|
|
|
zeta_0 = mju_in * cos_psi_in - sin_1 * sin_psi * cos_phi_0 |
|
85
|
|
|
ksi_0 = mju_in * sin_psi + sin_1 * cos_psi_in * cos_phi_0 |
|
86
|
|
|
|
|
87
|
|
|
cos_psi_out = ((cos_psi_in * r - delta * zeta_0) / |
|
88
|
|
|
np.sqrt((r * cos_psi_in - delta * zeta_0)**2 + |
|
89
|
|
|
(r * sin_psi - delta * ksi_0)**2 + |
|
90
|
|
|
(delta * sin_1 * sin_phi_0)**2)) |
|
91
|
|
|
sin_psi_out = np.sqrt(1.0 - np.clip(cos_psi_out * cos_psi_out, 1.0, np.inf)) |
|
92
|
|
|
#sin_psi_out = np.sqrt(1.0 - np.clip(cos_psi_out*cos_psi_out, -np.inf, 1.0)); |
|
93
|
|
|
|
|
94
|
|
|
eta_0 = ((r - delta * mju_in) * sin_psi * cos_phi_0 - delta * sin_1 * cos_psi_in) / (earth_radius + z_out) |
|
95
|
|
|
|
|
96
|
|
|
eta_0 = eta_0 + 1.0e-39 # /*! numerical stabilization*/ |
|
97
|
|
|
|
|
98
|
|
|
s1 = eta_0 / np.sqrt(eta_0**2 + (sin_psi * sin_phi_0)**2) |
|
99
|
|
|
s1 = s1 - sign(1.0e-13, s1) # /* ! numerical stabilization*/ |
|
100
|
|
|
|
|
101
|
|
|
sd = r * sin_psi * sin_1 * sin_phi_0 / (earth_radius + z_out) / (sin_psi_out * sin_out + 1.0e-78) |
|
102
|
|
|
|
|
103
|
|
|
phi_out = sign(np.arccos(s1), sd) |
|
104
|
|
|
|
|
105
|
|
|
sza_out = np.degrees(np.arccos(cos_psi_out)) |
|
106
|
|
|
los_out = np.degrees(np.arccos(mju_out)) |
|
107
|
|
|
saa_out = np.degrees(phi_out) |
|
108
|
|
|
# /* set back direction of line of sight |
|
109
|
|
|
# if (z_out > z_in) |
|
110
|
|
|
# *saa_out -= PI; */ |
|
111
|
|
|
logging.debug("calculated tangent_height: %s", h_0) |
|
112
|
|
|
return (sza_out, los_out, saa_out) |
|
113
|
|
|
|
|
114
|
1 |
|
def _middle_coord(lat1, lon1, lat2, lon2): |
|
115
|
|
|
sin_lat = 0.5 * (np.sin(np.radians(lat1)) + np.sin(np.radians(lat2))) |
|
116
|
|
|
cos_lat = 0.5 * (np.cos(np.radians(lat1)) + np.cos(np.radians(lat2))) |
|
117
|
|
|
sin_lon = 0.5 * (np.sin(np.radians(lon1)) + np.sin(np.radians(lon2))) |
|
118
|
|
|
cos_lon = 0.5 * (np.cos(np.radians(lon1)) + np.cos(np.radians(lon2))) |
|
119
|
|
|
return (np.degrees(np.arctan2(sin_lat, cos_lat)), |
|
120
|
|
|
np.degrees(np.arctan2(sin_lon, cos_lon))) |
|
121
|
|
|
|
|
122
|
1 |
|
_state_txt = { |
|
123
|
|
|
27: "SCIAMACHY limb eclips", |
|
124
|
|
|
28: "SCIAMACHY limb", |
|
125
|
|
|
29: "SCIAMACHY limb", |
|
126
|
|
|
30: "SCIAMACHY limb", |
|
127
|
|
|
31: "SCIAMACHY limb", |
|
128
|
|
|
32: "SCIAMACHY limb", |
|
129
|
|
|
33: "SCIAMACHY limb", |
|
130
|
|
|
55: "SCIAMACHY limb mesosp", |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
1 |
|
def read_hdf5_limb_state_common_data(self, hf, lstate_id, state_in_orbit, cl_id): |
|
134
|
|
|
"""SCIAMACHY level 1c common data |
|
135
|
|
|
|
|
136
|
|
|
Parameters |
|
137
|
|
|
---------- |
|
138
|
|
|
hf : opened file |
|
139
|
|
|
Pointer to the opened level 1c HDF5 file |
|
140
|
|
|
lstate_id : int |
|
141
|
|
|
The limb state id. |
|
142
|
|
|
state_in_orbit : int |
|
143
|
|
|
The number in this batch of states for the header. |
|
144
|
|
|
cl_id : int |
|
145
|
|
|
The spectral cluster number. |
|
146
|
|
|
|
|
147
|
|
|
Returns |
|
148
|
|
|
------- |
|
149
|
|
|
success : int |
|
150
|
|
|
0 on success, |
|
151
|
|
|
1 if an error occurred, for example if the measurement data |
|
152
|
|
|
set for the requested limb and cluster ids is empty. |
|
153
|
|
|
""" |
|
154
|
|
|
# MDS = measurement data set |
|
155
|
|
|
cl_mds_group_name = "/MDS/limb_{0:02d}/cluster_{1:02d}".format(lstate_id, cl_id + 1) |
|
156
|
|
|
cl_mds_group = hf.get(cl_mds_group_name) |
|
157
|
|
|
if cl_mds_group is None: |
|
158
|
|
|
return 1 |
|
159
|
|
|
# Load meta data |
|
160
|
|
|
self.metadata["calibration"] = hf.attrs["Calibration"].decode() |
|
161
|
|
|
self.metadata["l1b_product"] = hf.get("/MPH")["product_name"][0].decode() |
|
162
|
|
|
self.metadata["orbit"] = hf.get("/MPH")["abs_orbit"][0] |
|
163
|
|
|
self.metadata["state_id"] = hf.get("/ADS/STATES")["state_id"][lstate_id] |
|
164
|
|
|
self.metadata["software_version"] = hf.get("/MPH")["software_version"][0].decode() |
|
165
|
|
|
self.metadata["keyfile_version"] = hf.get("/SPH")["key_data_version"][0].decode() |
|
166
|
|
|
self.metadata["mfactor_version"] = hf.get("/SPH")["m_factor_version"][0].decode() |
|
167
|
|
|
init_ver = hf.get("/SPH")["init_version"][0].decode().strip() |
|
168
|
|
|
self.metadata["init_version"], decont = init_ver.split() |
|
169
|
|
|
self.metadata["decont_flags"] = decont.lstrip("DECONT=") |
|
170
|
|
|
orb_phase = hf.get("/ADS/STATES")["orb_phase"][lstate_id] |
|
171
|
|
|
j_day_0 = 2451544.5 # 2000-01-01 |
|
172
|
|
|
dsr_d, dsr_s, dsr_us = hf.get("/ADS/STATES")["dsr_time"][lstate_id] |
|
173
|
|
|
state_dt = Time(dsr_d + j_day_0 + dsr_s / 86400. + dsr_us / (86400. * 1e6), |
|
174
|
|
|
format="jd").datetime |
|
175
|
|
|
self.metadata["date"] = state_dt.strftime("%d-%b-%Y %H:%M:%S.%f") |
|
176
|
|
|
|
|
177
|
|
|
logging.debug("applied calibrations: %s", self.metadata["calibration"]) |
|
178
|
|
|
logging.debug("product: %s, orbit_nr: %s, state_id: %s, orb_phase: %s", |
|
179
|
|
|
self.metadata["l1b_product"], self.metadata["orbit"], |
|
180
|
|
|
self.metadata["state_id"], orb_phase) |
|
181
|
|
|
logging.debug("soft_ver: %s, key_ver: %s, mf_ver: %s, init_ver: %s, " |
|
182
|
|
|
"decont_ver: %s", self.metadata["software_version"], |
|
183
|
|
|
self.metadata["keyfile_version"], self.metadata["mfactor_version"], |
|
184
|
|
|
self.metadata["init_version"], self.metadata["decont_flags"]) |
|
185
|
|
|
|
|
186
|
|
|
ads_state = hf.get("/ADS/STATES")[lstate_id] |
|
187
|
|
|
cl_n_readouts = ads_state["clus_config"]["num_readouts"][cl_id] |
|
188
|
|
|
cl_intg_time = ads_state["clus_config"]["intg_time"][cl_id] |
|
189
|
|
|
self.metadata["nr_profile"] = 24 // (cl_intg_time * cl_n_readouts) |
|
190
|
|
|
self.metadata["act_profile"] = 0 # always zero for now |
|
191
|
|
|
|
|
192
|
|
|
# Prepare the header |
|
193
|
|
|
try: |
|
194
|
|
|
self.metadata["datatype_txt"] = _state_txt[self.metadata["state_id"]] |
|
195
|
|
|
except KeyError: |
|
196
|
|
|
logging.warn("State id %s not supported.", self.metadata["state_id"]) |
|
197
|
|
|
return 1 |
|
198
|
|
|
self.assemble_textheader() |
|
199
|
|
|
logging.debug("header:\n%s", self.textheader) |
|
200
|
|
|
|
|
201
|
|
|
# parse geolocation data |
|
202
|
|
|
gr_scia_geo = cl_mds_group.get("geoL_scia") |
|
203
|
|
|
tan_h = gr_scia_geo["tan_h"] |
|
204
|
|
|
# lat and lon are integers in degrees * 10^6 |
|
205
|
|
|
lats_all = gr_scia_geo["tang_ground_point"]["lat"] |
|
206
|
|
|
lons_all = gr_scia_geo["tang_ground_point"]["lon"] |
|
207
|
|
|
sza_all = gr_scia_geo["sun_zen_ang"] |
|
208
|
|
|
saa_all = (gr_scia_geo["sun_azi_ang"] - gr_scia_geo["los_azi_ang"]) |
|
209
|
|
|
sat_h_all = gr_scia_geo["sat_h"] |
|
210
|
|
|
earth_rad_all = gr_scia_geo["earth_rad"] |
|
211
|
|
|
# lat and lon are integers in degrees * 10^6 |
|
212
|
|
|
subsatlat_all = gr_scia_geo["sub_sat_point"]["lat"] |
|
213
|
|
|
subsatlon_all = gr_scia_geo["sub_sat_point"]["lon"] |
|
214
|
|
|
# fix longitudes to [0°, 360°) |
|
215
|
|
|
lons_all[np.where(lons_all < 0)] += 360000000 |
|
216
|
|
|
|
|
217
|
|
|
if cl_n_readouts > 2: |
|
218
|
|
|
tangent_heights = 0.5 * (tan_h[1::cl_n_readouts, 2] + tan_h[2::cl_n_readouts, 0]) |
|
219
|
|
|
tp_lats = 0.5 * (lats_all[1::cl_n_readouts, 2] + lats_all[2::cl_n_readouts, 0]) * 1e-6 |
|
220
|
|
|
tp_lons = 0.5 * (lons_all[1::cl_n_readouts, 2] + lons_all[2::cl_n_readouts, 0]) * 1e-6 |
|
221
|
|
|
sza_toa = 0.5 * (sza_all[1::cl_n_readouts, 2] + sza_all[2::cl_n_readouts, 0]) |
|
222
|
|
|
saa_toa = 0.5 * (saa_all[1::cl_n_readouts, 2] + saa_all[2::cl_n_readouts, 0]) |
|
223
|
|
|
sat_hs = sat_h_all.reshape((-1, cl_n_readouts)).mean(axis=1) |
|
224
|
|
|
earth_rads = earth_rad_all.reshape((-1, cl_n_readouts)).mean(axis=1) |
|
225
|
|
|
subsatlat = subsatlat_all.reshape((-1, cl_n_readouts)).mean(axis=1) * 1e-6 |
|
226
|
|
|
subsatlon = subsatlon_all.reshape((-1, cl_n_readouts)).mean(axis=1) * 1e-6 |
|
227
|
|
|
else: |
|
228
|
|
|
tangent_heights = tan_h[::cl_n_readouts, 1] |
|
229
|
|
|
tp_lats = lats_all[::cl_n_readouts, 1] * 1e-6 |
|
230
|
|
|
tp_lons = lons_all[::cl_n_readouts, 1] * 1e-6 |
|
231
|
|
|
sza_toa = sza_all[::cl_n_readouts, 1] |
|
232
|
|
|
saa_toa = saa_all[::cl_n_readouts, 1] |
|
233
|
|
|
sat_hs = sat_h_all[::cl_n_readouts] |
|
234
|
|
|
earth_rads = earth_rad_all[::cl_n_readouts] |
|
235
|
|
|
subsatlat = subsatlat_all[::cl_n_readouts] * 1e-6 |
|
236
|
|
|
subsatlon = subsatlon_all[::cl_n_readouts] * 1e-6 |
|
237
|
|
|
|
|
238
|
|
|
logging.debug("tangent altitudes: %s", tangent_heights) |
|
239
|
|
|
nalt = len(tangent_heights) |
|
240
|
|
|
|
|
241
|
|
|
centre = _middle_coord(lats_all[0, 1] * 1e-6, lons_all[0, 1] * 1e-6, |
|
242
|
|
|
lats_all[nalt - 2, 1] * 1e-6, lons_all[nalt - 2, 1] * 1e-6) |
|
243
|
|
|
|
|
244
|
|
|
cent_lat_lon = (centre[0], |
|
245
|
|
|
# fix longitudes to [0, 360.) |
|
246
|
|
|
centre[1] if centre[1] >= 0. else 360. + centre[1], |
|
247
|
|
|
lats_all[0, 0] * 1e-6, lons_all[0, 0] * 1e-6, |
|
248
|
|
|
lats_all[0, 2] * 1e-6, lons_all[0, 2] * 1e-6, |
|
249
|
|
|
lats_all[nalt - 2, 0] * 1e-6, lons_all[nalt - 2, 0] * 1e-6, |
|
250
|
|
|
lats_all[nalt - 2, 2] * 1e-6, lons_all[nalt - 2, 2] * 1e-6) |
|
251
|
|
|
|
|
252
|
|
|
toa = 100. |
|
253
|
|
|
# to satellite first |
|
254
|
|
|
los_calc = np.degrees(np.arccos(0.0)) |
|
255
|
|
|
sza_tp_h = sza_toa.copy() |
|
256
|
|
|
saa_tp_h = saa_toa.copy() |
|
257
|
|
|
los_tp_h = np.full_like(tangent_heights, los_calc) |
|
258
|
|
|
los_toa_h = np.full_like(tangent_heights, los_calc) |
|
259
|
|
|
sza_sat_h, los_sat_h, saa_sat_h = _calc_angles( |
|
260
|
|
|
sza_toa, los_calc, saa_toa, |
|
261
|
|
|
tangent_heights, sat_hs, earth_rads) |
|
262
|
|
|
# angles toa |
|
263
|
|
|
los_calc = np.degrees(np.arcsin((tangent_heights + earth_rads) / (toa + earth_rads))) |
|
264
|
|
|
# to tangent point |
|
265
|
|
|
los_toa_l = np.full_like(tangent_heights, los_calc) |
|
266
|
|
|
sza_tp_l, los_tp_l, saa_tp_l = _calc_angles( |
|
267
|
|
|
sza_toa, los_calc, saa_toa, |
|
268
|
|
|
np.full_like(tangent_heights, toa), tangent_heights, |
|
269
|
|
|
earth_rads) |
|
270
|
|
|
# to satellite |
|
271
|
|
|
sza_sat_l, los_sat_l, saa_sat_l = _calc_angles( |
|
272
|
|
|
sza_toa, los_calc, saa_toa, |
|
273
|
|
|
np.full_like(tangent_heights, toa), sat_hs, |
|
274
|
|
|
earth_rads) |
|
275
|
|
|
|
|
276
|
|
|
sza_sat_h[np.where(tangent_heights <= toa)] = 0. |
|
277
|
|
|
sza_sat_l[np.where(tangent_heights > toa)] = 0. |
|
278
|
|
|
saa_sat_h[np.where(tangent_heights <= toa)] = 0. |
|
279
|
|
|
saa_sat_l[np.where(tangent_heights > toa)] = 0. |
|
280
|
|
|
los_sat_h[np.where(tangent_heights <= toa)] = 0. |
|
281
|
|
|
los_sat_l[np.where(tangent_heights > toa)] = 0. |
|
282
|
|
|
|
|
283
|
|
|
sza_tp_h[np.where(tangent_heights <= toa)] = 0. |
|
284
|
|
|
sza_tp_l[np.where(tangent_heights > toa)] = 0. |
|
285
|
|
|
saa_tp_h[np.where(tangent_heights <= toa)] = 0. |
|
286
|
|
|
saa_tp_l[np.where(tangent_heights > toa)] = 0. |
|
287
|
|
|
los_tp_h[np.where(tangent_heights <= toa)] = 0. |
|
288
|
|
|
los_tp_l[np.where(tangent_heights > toa)] = 0. |
|
289
|
|
|
|
|
290
|
|
|
los_toa_h[np.where(tangent_heights <= toa)] = 0. |
|
291
|
|
|
los_toa_l[np.where(tangent_heights > toa)] = 0. |
|
292
|
|
|
|
|
293
|
|
|
sza_sat = sza_sat_h + sza_sat_l |
|
294
|
|
|
saa_sat = saa_sat_h + saa_sat_l |
|
295
|
|
|
los_sat = los_sat_h + los_sat_l |
|
296
|
|
|
|
|
297
|
|
|
sza_tp = sza_tp_h + sza_tp_l |
|
298
|
|
|
saa_tp = saa_tp_h + saa_tp_l |
|
299
|
|
|
los_tp = los_tp_h + los_tp_l |
|
300
|
|
|
|
|
301
|
|
|
los_toa = los_toa_h + los_toa_l |
|
302
|
|
|
|
|
303
|
|
|
logging.debug("TP sza, saa, los: %s, %s, %s", sza_tp, saa_tp, los_tp) |
|
304
|
|
|
logging.debug("TOA sza, saa, los: %s, %s, %s", sza_toa, saa_toa, los_toa) |
|
305
|
|
|
logging.debug("SAT sza, saa, los: %s, %s, %s", sza_sat, saa_sat, los_sat) |
|
306
|
|
|
|
|
307
|
|
|
# save the data to the limb scan class |
|
308
|
|
|
self.nalt = nalt |
|
309
|
|
|
self.orbit_state = (self.metadata["orbit"], state_in_orbit, |
|
310
|
|
|
self.metadata["state_id"], |
|
311
|
|
|
self.metadata["nr_profile"], self.metadata["act_profile"]) |
|
312
|
|
|
self.date = (state_dt.year, state_dt.month, state_dt.day, |
|
313
|
|
|
state_dt.hour, state_dt.minute, state_dt.second) |
|
314
|
|
|
self.orbit_phase = orb_phase |
|
315
|
|
|
self.cent_lat_lon = cent_lat_lon |
|
316
|
|
|
# pre-set the limb_data |
|
317
|
|
|
if self._limb_data_dtype is None: |
|
318
|
|
|
self._limb_data_dtype = _limb_data_dtype[:] |
|
319
|
|
|
self.limb_data = np.zeros((self.nalt), dtype=self._limb_data_dtype) |
|
320
|
|
|
self.limb_data["sub_sat_lat"] = subsatlat |
|
321
|
|
|
self.limb_data["sub_sat_lon"] = subsatlon |
|
322
|
|
|
self.limb_data["tp_lat"] = tp_lats |
|
323
|
|
|
self.limb_data["tp_lon"] = tp_lons |
|
324
|
|
|
self.limb_data["tp_alt"] = tangent_heights |
|
325
|
|
|
self.limb_data["tp_sza"] = sza_tp |
|
326
|
|
|
self.limb_data["tp_saa"] = saa_tp |
|
327
|
|
|
self.limb_data["tp_los"] = los_tp |
|
328
|
|
|
self.limb_data["toa_sza"] = sza_toa |
|
329
|
|
|
self.limb_data["toa_saa"] = saa_toa |
|
330
|
|
|
self.limb_data["toa_los"] = los_toa |
|
331
|
|
|
self.limb_data["sat_sza"] = sza_sat |
|
332
|
|
|
self.limb_data["sat_saa"] = saa_sat |
|
333
|
|
|
self.limb_data["sat_los"] = los_sat |
|
334
|
|
|
self.limb_data["sat_alt"] = sat_hs |
|
335
|
|
|
self.limb_data["earth_rad"] = earth_rads |
|
336
|
|
|
return 0 |
|
337
|
|
|
|
|
338
|
1 |
|
def read_hdf5_limb_state_spectral_data(self, hf, lstate_id, cl_id): |
|
339
|
|
|
"""SCIAMACHY level 1c spectral data |
|
340
|
|
|
|
|
341
|
|
|
Parameters |
|
342
|
|
|
---------- |
|
343
|
|
|
hf : opened file |
|
344
|
|
|
Pointer to the opened level 1c HDF5 file |
|
345
|
|
|
lstate_id : int |
|
346
|
|
|
The limb state id. |
|
347
|
|
|
cl_id : int |
|
348
|
|
|
The spectral cluster number. |
|
349
|
|
|
|
|
350
|
|
|
Returns |
|
351
|
|
|
------- |
|
352
|
|
|
success : int |
|
353
|
|
|
0 on success, |
|
354
|
|
|
1 if an error occurred, for example if the measurement data |
|
355
|
|
|
set for the requested limb and cluster ids is empty. |
|
356
|
|
|
""" |
|
357
|
|
|
cl_mds_group_name = "/MDS/limb_{0:02d}/cluster_{1:02d}".format(lstate_id, cl_id + 1) |
|
358
|
|
|
cl_mds_group = hf.get(cl_mds_group_name) |
|
359
|
|
|
if cl_mds_group is None: |
|
360
|
|
|
return 1 |
|
361
|
|
|
|
|
362
|
|
|
ads_state = hf.get("/ADS/STATES")[lstate_id] |
|
363
|
|
|
cl_n_readouts = ads_state["clus_config"]["num_readouts"][cl_id] |
|
364
|
|
|
|
|
365
|
|
|
pwl = cl_mds_group.get("pixel_wavelength")[:] |
|
366
|
|
|
signal = cl_mds_group.get("pixel_signal")[:] |
|
367
|
|
|
sig_errs = cl_mds_group.get("pixel_signal_error")[:] |
|
368
|
|
|
if cl_n_readouts > 1: |
|
369
|
|
|
# coadd data |
|
370
|
|
|
signal_coadd = signal.reshape((-1, cl_n_readouts, len(pwl))).sum(axis=1) |
|
371
|
|
|
sig_errs = np.sqrt(((sig_errs * signal)**2) |
|
372
|
|
|
.reshape((-1, cl_n_readouts, len(pwl))) |
|
373
|
|
|
.sum(axis=1)) / np.abs(signal_coadd) |
|
374
|
|
|
signal = signal_coadd / cl_n_readouts |
|
375
|
|
|
if np.any(self.wls): |
|
376
|
|
|
# apparently we already have some data, so concatenate |
|
377
|
|
|
self.wls = np.concatenate([self.wls, pwl], axis=0) |
|
378
|
|
|
self._rad_arr = np.concatenate([self._rad_arr, signal], axis=1) |
|
379
|
|
|
self._err_arr = np.concatenate([self._err_arr, sig_errs], axis=1) |
|
380
|
|
|
else: |
|
381
|
|
|
# this seems to be the first time we fill the arrays |
|
382
|
|
|
self.wls = pwl |
|
383
|
|
|
self._rad_arr = signal |
|
384
|
|
|
self._err_arr = sig_errs |
|
385
|
|
|
return 0 |
|
386
|
|
|
|
|
387
|
1 |
|
def read_from_hdf5(self, hf, limb_state_id, state_in_orbit, cluster_ids): |
|
388
|
|
|
"""SCIAMACHY level 1c HDF main interface |
|
389
|
|
|
|
|
390
|
|
|
This should be the function to be used for HDF5 reading. |
|
391
|
|
|
It reads the common data and iterates over the spectral |
|
392
|
|
|
clusters to fill the class data. |
|
393
|
|
|
|
|
394
|
|
|
Parameters |
|
395
|
|
|
---------- |
|
396
|
|
|
hf : opened file |
|
397
|
|
|
Pointer to the opened level 1c HDF5 file |
|
398
|
|
|
limb_state_id : int |
|
399
|
|
|
The limb state id. |
|
400
|
|
|
state_in_orbit : int |
|
401
|
|
|
The number in this batch of states for the header. |
|
402
|
|
|
cluster_ids : int or sequence of ints |
|
403
|
|
|
The spectral cluster numbers. |
|
404
|
|
|
|
|
405
|
|
|
Returns |
|
406
|
|
|
------- |
|
407
|
|
|
success : int |
|
408
|
|
|
0 on success, |
|
409
|
|
|
1 if an error occurred, for example if the measurement data |
|
410
|
|
|
set for the requested limb and cluster ids is empty. |
|
411
|
|
|
""" |
|
412
|
|
|
import numpy.lib.recfunctions as rfn |
|
413
|
|
|
if not hasattr(cluster_ids, '__getitem__'): |
|
414
|
|
|
cluster_ids = [cluster_ids] |
|
415
|
|
|
|
|
416
|
|
|
if self.read_hdf5_limb_state_common_data(hf, limb_state_id, |
|
417
|
|
|
state_in_orbit, cluster_ids[0]): |
|
418
|
|
|
return 1 |
|
419
|
|
|
|
|
420
|
|
|
for cl_id in cluster_ids: |
|
421
|
|
|
self.read_hdf5_limb_state_spectral_data(hf, limb_state_id, cl_id) |
|
422
|
|
|
|
|
423
|
|
|
self.npix = len(self.wls) |
|
424
|
|
|
|
|
425
|
|
|
rads = np.rec.fromarrays([self._rad_arr], |
|
426
|
|
|
dtype=np.dtype([("rad", 'f4', (self.npix,))])) |
|
427
|
|
|
errs = np.rec.fromarrays([self._err_arr], |
|
428
|
|
|
dtype=np.dtype([("err", 'f4', (self.npix,))])) |
|
429
|
|
|
self.limb_data = rfn.merge_arrays([self.limb_data, rads, errs], |
|
430
|
|
|
usemask=False, asrecarray=True, flatten=True) |
|
431
|
|
|
self._limb_data_dtype = self.limb_data.dtype |
|
432
|
|
|
|
|
433
|
|
|
return 0 |
|
434
|
|
|
|