s2-rut-python 0.0.1__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.
third-party/run_rut.py ADDED
@@ -0,0 +1,303 @@
1
+ #!/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ @author: aderu
5
+ """
6
+
7
+ import os, sys
8
+ import json
9
+ import argparse
10
+ import shutil
11
+ from matplotlib import pyplot as plt
12
+ import numpy as np
13
+ import netCDF4 as nc
14
+ from mpl_toolkits.axes_grid1 import make_axes_locatable
15
+ from Source.S2Reader import S2Processor
16
+ from Source.S2RUT import S2RUT_L1
17
+
18
+ S2_BAND_NAMES = [
19
+ "B01",
20
+ "B02",
21
+ "B03",
22
+ "B04",
23
+ "B05",
24
+ "B06",
25
+ "B07",
26
+ "B08",
27
+ "B8A",
28
+ "B09",
29
+ "B10",
30
+ "B11",
31
+ "B12",
32
+ ]
33
+ S2_BAND_SAMPLING = {
34
+ "B01": 60,
35
+ "B02": 10,
36
+ "B03": 10,
37
+ "B04": 10,
38
+ "B05": 20,
39
+ "B06": 20,
40
+ "B07": 20,
41
+ "B08": 10,
42
+ "B8A": 20,
43
+ "B09": 60,
44
+ "B10": 60,
45
+ "B11": 20,
46
+ "B12": 20,
47
+ }
48
+
49
+
50
+ def json_none(param):
51
+ if param == "None" or param == "":
52
+ return None
53
+ else:
54
+ return float(param)
55
+
56
+
57
+ def run_s2rut_image(config):
58
+ """
59
+ S2-L1C uncertainty computation for full image or AOI, without spectral error correlation.
60
+ Work band per band to minimize RAM consumption.
61
+
62
+ Parameters
63
+ ----------
64
+ config : str, path of config file
65
+
66
+ Returns
67
+ -------
68
+ Save uncertainty product in reflectance dimension
69
+
70
+ """
71
+
72
+ # check if inputs bands are not none
73
+ if config["input_bands"] is None:
74
+ bandlist = S2_BAND_NAMES
75
+ else:
76
+ bandlist = config["input_bands"]
77
+
78
+ # check uncertainty type to output
79
+ fname = os.path.basename(config["input_L1C"]).split(".")[0]
80
+
81
+ print("S2 RUT L1: image/AOI uncertainty")
82
+ print("Processing:", os.path.basename(config["input_L1C"]))
83
+ print("Processing bands:", bandlist)
84
+ do_plot = config["doplot"]
85
+ do_cont = config["unc_per_contributor"]
86
+ if do_cont:
87
+ print("warning: computing unc contributors takes a long time!")
88
+
89
+ # process individually each band to avoid RAM consumption in case of full image
90
+ for i, band in enumerate(bandlist):
91
+ print(band)
92
+ s2proc = S2Processor()
93
+ s2proc.product = config["input_L1C"]
94
+ s2proc.noise_model = config["input_noise_model"]
95
+ s2proc.output = config["path_output"]
96
+ s2proc.selected_bands = [band]
97
+ s2proc.lat_centre = json_none(config["roi_lat"])
98
+ s2proc.lon_centre = json_none(config["roi_lon"])
99
+ s2proc.w = json_none(config["roi_width"])
100
+ s2proc.h = json_none(config["roi_height"])
101
+
102
+ # check if roi size is larger than 1 pixel
103
+ roi_pix_x = json_none(config["roi_width"]) / S2_BAND_SAMPLING[band]
104
+ roi_pix_y = json_none(config["roi_height"]) / S2_BAND_SAMPLING[band]
105
+ if roi_pix_x < 2 or roi_pix_y < 2:
106
+ print("ERROR: ROI size is less than 2 pixels, skipping band")
107
+ continue
108
+
109
+ # retrieve L1C radiometry
110
+ s2proc.get_data(get_va=False, doplot=False)
111
+ img = s2proc.L1C_ref[0]
112
+
113
+ # Compute uncertainty (absolute value, in reflectance dimension)
114
+ RUTl1 = S2RUT_L1(config["input_contributors"])
115
+ u_ref, u_cont = RUTl1.unc_calculation_abs(
116
+ img, band, 0, s2proc.metadatadict, s2proc.sun_zenith, do_contributor=do_cont
117
+ )
118
+
119
+ # write output product
120
+ newfile = os.path.join(s2proc.output, fname, band + "_unc_abs.jp2")
121
+ s2proc.write_unc(u_ref, newfile, band, s2proc.ds_profile[0])
122
+ if do_cont:
123
+ # write each contributor
124
+ for u in u_cont.keys():
125
+ print(" ", u)
126
+ newfile = os.path.join(
127
+ s2proc.output, fname, "contributors", band + "_" + u + ".jp2"
128
+ )
129
+ s2proc.write_unc(u_cont[u], newfile, band, s2proc.ds_profile[0])
130
+
131
+ # copy input parameter for tracing configuration
132
+ shutil.copy2(config["input_contributors"], os.path.dirname(newfile))
133
+
134
+ # Plot
135
+ if do_plot:
136
+ fig1, ax1 = plt.subplots(1, 2, figsize=(8, 5))
137
+ plt.subplots_adjust(
138
+ left=0.05, bottom=0.1, right=0.9, top=0.9, wspace=0.3, hspace=0.1
139
+ )
140
+ im0 = ax1[0].imshow(img, interpolation="None")
141
+ ax1[0].set_title(band + " Reflectance")
142
+ divider = make_axes_locatable(ax1[0])
143
+ cax = divider.append_axes("right", size="5%", pad=0.05)
144
+ cb = fig1.colorbar(
145
+ im0, cax=cax, orientation="vertical", label="Reflectance"
146
+ )
147
+ cb.ax.tick_params(labelsize=8)
148
+
149
+ img[img == 0] = np.nan
150
+ im1 = ax1[1].imshow(
151
+ u_ref * 100 / img,
152
+ interpolation="None",
153
+ vmax=np.nanmean(u_ref * 100 / img) * 3,
154
+ )
155
+ ax1[1].set_title(band + " Uncertainties ")
156
+ divider = make_axes_locatable(ax1[1])
157
+ cax = divider.append_axes("right", size="5%", pad=0.05)
158
+ cb = fig1.colorbar(im1, cax=cax, orientation="vertical", label="unc [%]")
159
+ cb.ax.tick_params(labelsize=8)
160
+
161
+ for ax in ax1:
162
+ ax.tick_params(axis="both", which="major", labelsize=8)
163
+ fig1.savefig(os.path.join(s2proc.output, fname, band + "_unc_plot.png"))
164
+
165
+ del u_ref, u_cont
166
+
167
+ # Show all plots at once
168
+ plt.show()
169
+ print("Output files written in", config["path_output"])
170
+
171
+
172
+ def run_s2rut_spectralcorr(config):
173
+ """
174
+ S2-L1C uncertainty computation with spectral error correlation.
175
+ Uncetainties computed for all bands, but only for a single pixel.
176
+ !!! NOT AVAILABLE YET !!!
177
+
178
+ Parameters
179
+ ----------
180
+ config : str, path of config file
181
+
182
+ Returns
183
+ -------
184
+ None.
185
+
186
+ """
187
+
188
+ print("S2 RUT L1: spectral error correlation uncertainty")
189
+ print("Only available for a single pixel : AOI size set to 1 pixel")
190
+ do_plot = config["doplot"]
191
+
192
+ s2proc = S2Processor()
193
+ s2proc.product = config["input_L1C"]
194
+ s2proc.noise_model = config["input_noise_model"]
195
+ s2proc.output = config["path_output"]
196
+ s2proc.lat_centre = json_none(config["roi_lat"])
197
+ s2proc.lon_centre = json_none(config["roi_lon"])
198
+
199
+ # hard coded parameters in this mode
200
+ s2proc.selected_bands = [
201
+ "B01",
202
+ "B02",
203
+ "B03",
204
+ "B04",
205
+ "B05",
206
+ "B06",
207
+ "B07",
208
+ "B08",
209
+ "B09",
210
+ "B10",
211
+ "B11",
212
+ "B12",
213
+ ]
214
+ s2proc.w = 1
215
+ s2proc.h = 1
216
+
217
+ # Retrieve L1C radiometry
218
+ s2proc.get_data(get_va=False, doplot=False)
219
+
220
+ # Compute uncertainty
221
+ RUTl1 = S2RUT_L1(config["input_contributors"])
222
+ unc = []
223
+ for i, band in enumerate(s2proc.selected_bands):
224
+ # u_ref, u_sig, u_sys, u_cont = RUTl1.unc_calculation(s2proc.L1C_ref[i], band, s2proc.metadatadict, s2proc.sun_zenith)
225
+ u_ref = RUTl1.unc_calculation(
226
+ s2proc.L1C_ref[i], band, i, s2proc.metadatadict, s2proc.sun_zenith
227
+ )
228
+ unc.append(u_ref)
229
+
230
+ # Compute Spectral Error correlation
231
+ nsamp = config["SEC_sample"]
232
+ u_corr = np.array(
233
+ RUTl1.unc_spectralcorrelation(s2proc.L1C_rad, s2proc.metadatadict, nsamp)
234
+ )
235
+
236
+ # write output
237
+ fname = os.path.basename(config["input_L1C"]).split(".")[0]
238
+ new_file = os.path.join(
239
+ config["path_output"], fname, "spectral_err_corr_" + str(nsamp) + ".nc"
240
+ )
241
+ s2proc.write_spectral_corr_error(unc, u_corr, new_file)
242
+
243
+ if do_plot:
244
+ plt.figure()
245
+ plt.plot(np.squeeze(unc))
246
+ plt.title("unc for given pixel")
247
+ plt.xlabel("bands")
248
+ plt.ylabel("unc [%]")
249
+
250
+ plt.figure()
251
+ for i in range(nsamp):
252
+ plt.plot(u_corr[:, i])
253
+ plt.title("unc spectral correlation per band")
254
+ plt.xlabel("bands")
255
+ plt.ylabel("unc [%]")
256
+
257
+ # Show all plots at once
258
+ plt.show()
259
+
260
+ fname = os.path.join(
261
+ config["path_output"],
262
+ os.path.basename(config["input_L1C"]).split(".")[0] + ".nc",
263
+ )
264
+ f = nc.Dataset(fname, "w", format="NETCDF4")
265
+ f.createDimension("bands", len(s2proc.selected_bands))
266
+ f.createDimension("sample", config["SEC_sample"])
267
+ var1 = f.createVariable("pixel_unc", "f4", ("bands"))
268
+ var2 = f.createVariable("spectral_correlation_error", "f4", ("bands", "sample"))
269
+ var1[:] = np.squeeze(unc)
270
+ var2[:] = u_corr
271
+ f.history = "S2-RUT-L1 spectrale correlation error"
272
+ f.close()
273
+
274
+
275
+ #### MAIN
276
+ if __name__ == "__main__":
277
+ parser = argparse.ArgumentParser(
278
+ formatter_class=argparse.RawDescriptionHelpFormatter,
279
+ description="S2-RUT-L1C tool",
280
+ )
281
+ parser.add_argument("config_file", help="path of RUT config file")
282
+ args = parser.parse_args()
283
+
284
+ # try:
285
+ # Read config file
286
+ with open(args.config_file) as f:
287
+ config = json.load(f)
288
+
289
+ # check if contributor file exists
290
+ fcontrib = config["input_contributors"]
291
+ if not os.path.exists(fcontrib):
292
+ print("ERROR: uncertainty contributor file is missing")
293
+ print("check Data/input_contributors.json in repository")
294
+ sys.exit()
295
+
296
+ # launch RUT
297
+ run_s2rut_image(config)
298
+
299
+ # except Exception as error:
300
+ # print("An error occurred:", error)
301
+ # exc_type, exc_obj, exc_tb = sys.exc_info()
302
+ # fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
303
+ # print(exc_type, fname, exc_tb.tb_lineno)