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.
- docs/conf.py +149 -0
- examples/run_example.py +117 -0
- examples/temporary_example.py +202 -0
- s2_rut_python/__init__.py +9 -0
- s2_rut_python/_vendor.py +19 -0
- s2_rut_python/_version.py +21 -0
- s2_rut_python/interface.py +500 -0
- s2_rut_python/tests/__init__.py +0 -0
- s2_rut_python/tests/test_interface.py +291 -0
- s2_rut_python-0.0.1.dist-info/METADATA +127 -0
- s2_rut_python-0.0.1.dist-info/RECORD +18 -0
- s2_rut_python-0.0.1.dist-info/WHEEL +5 -0
- s2_rut_python-0.0.1.dist-info/licenses/LICENSE +165 -0
- s2_rut_python-0.0.1.dist-info/top_level.txt +4 -0
- third-party/Source/S2RUT.py +477 -0
- third-party/Source/S2Reader.py +695 -0
- third-party/Source/S2Reader_band.py +675 -0
- third-party/run_rut.py +303 -0
docs/conf.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#
|
|
3
|
+
# s2_rut_python documentation build configuration file, created by
|
|
4
|
+
# cookiecutter
|
|
5
|
+
#
|
|
6
|
+
# This file is execfile()d with the current directory set to its
|
|
7
|
+
# containing dir.
|
|
8
|
+
#
|
|
9
|
+
# Note that not all possible configuration values are present in this
|
|
10
|
+
# autogenerated file.
|
|
11
|
+
#
|
|
12
|
+
# All configuration values have a default; values that are commented out
|
|
13
|
+
# serve to show the default.
|
|
14
|
+
|
|
15
|
+
import s2_rut_python
|
|
16
|
+
|
|
17
|
+
project_title = "s2_rut_python".replace("_", " ").title()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# -- General configuration ---------------------------------------------
|
|
21
|
+
|
|
22
|
+
# If your documentation needs a minimal Sphinx version, state it here.
|
|
23
|
+
#
|
|
24
|
+
# needs_sphinx = '1.0'
|
|
25
|
+
|
|
26
|
+
# Attempt to make links automatially
|
|
27
|
+
default_role = "code"
|
|
28
|
+
|
|
29
|
+
# Add any Sphinx extension module names here, as strings. They can be
|
|
30
|
+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
|
31
|
+
# CFAB added napolean to support google-style docstrings
|
|
32
|
+
extensions = [
|
|
33
|
+
"sphinx.ext.autodoc",
|
|
34
|
+
"sphinx.ext.autosummary",
|
|
35
|
+
"sphinx.ext.intersphinx",
|
|
36
|
+
"sphinx.ext.viewcode",
|
|
37
|
+
"sphinx.ext.napoleon",
|
|
38
|
+
"IPython.sphinxext.ipython_directive",
|
|
39
|
+
"IPython.sphinxext.ipython_console_highlighting",
|
|
40
|
+
"sphinx_design",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
# Add any paths that contain templates here, relative to this directory.
|
|
44
|
+
templates_path = ["_templates"]
|
|
45
|
+
|
|
46
|
+
# The suffix(es) of source filenames.
|
|
47
|
+
# You can specify multiple suffix as a list of string:
|
|
48
|
+
#
|
|
49
|
+
# source_suffix = ['.rst', '.md']
|
|
50
|
+
source_suffix = ".rst"
|
|
51
|
+
|
|
52
|
+
# The master toctree document.
|
|
53
|
+
master_doc = "index"
|
|
54
|
+
|
|
55
|
+
# General information about the project.
|
|
56
|
+
project = project_title
|
|
57
|
+
copyright = "Jacob Fahy"
|
|
58
|
+
author = "Jacob Fahy"
|
|
59
|
+
|
|
60
|
+
# The version info for the project you're documenting, acts as replacement
|
|
61
|
+
# for |version| and |release|, also used in various other places throughout
|
|
62
|
+
# the built documents.
|
|
63
|
+
#
|
|
64
|
+
# The short X.Y version.
|
|
65
|
+
version = s2_rut_python.__version__
|
|
66
|
+
# The full version, including alpha/beta/rc tags.
|
|
67
|
+
release = s2_rut_python.__version__
|
|
68
|
+
|
|
69
|
+
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
70
|
+
# for a list of supported languages.
|
|
71
|
+
#
|
|
72
|
+
# This is also used if you do content translation via gettext catalogs.
|
|
73
|
+
# Usually you set "language" from the command line for these cases.
|
|
74
|
+
language = None
|
|
75
|
+
|
|
76
|
+
# List of patterns, relative to source directory, that match files and
|
|
77
|
+
# directories to ignore when looking for source files.
|
|
78
|
+
# This patterns also effect to html_static_path and html_extra_path
|
|
79
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
80
|
+
|
|
81
|
+
# The name of the Pygments (syntax highlighting) style to use.
|
|
82
|
+
pygments_style = "sphinx"
|
|
83
|
+
|
|
84
|
+
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
|
85
|
+
todo_include_todos = False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# -- Options for HTML output -------------------------------------------
|
|
89
|
+
|
|
90
|
+
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
91
|
+
# a list of builtin themes.
|
|
92
|
+
#
|
|
93
|
+
html_theme = "sphinx_book_theme"
|
|
94
|
+
|
|
95
|
+
# Theme options are theme-specific and customize the look and feel of a
|
|
96
|
+
# theme further. For a list of options available for each theme, see the
|
|
97
|
+
# documentation.
|
|
98
|
+
#
|
|
99
|
+
html_theme_options = {
|
|
100
|
+
"announcement": "<strong>Beta Version:</strong> This software is a beta version, results should be used with caution. Please share any feedback you have after using the tool.",
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Add any paths that contain custom static files (such as style sheets) here,
|
|
104
|
+
# relative to this directory. They are copied after the builtin static files,
|
|
105
|
+
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
106
|
+
html_static_path = ["_static"]
|
|
107
|
+
|
|
108
|
+
# -- Options for HTMLHelp output ---------------------------------------
|
|
109
|
+
|
|
110
|
+
# Output file base name for HTML help builder.
|
|
111
|
+
htmlhelp_basename = "s2_rut_pythondoc"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# -- Options for LaTeX output ------------------------------------------
|
|
115
|
+
|
|
116
|
+
latex_elements = {
|
|
117
|
+
# The paper size ('letterpaper' or 'a4paper').
|
|
118
|
+
#
|
|
119
|
+
# 'papersize': 'letterpaper',
|
|
120
|
+
# The font size ('10pt', '11pt' or '12pt').
|
|
121
|
+
#
|
|
122
|
+
# 'pointsize': '10pt',
|
|
123
|
+
# Additional stuff for the LaTeX preamble.
|
|
124
|
+
#
|
|
125
|
+
# 'preamble': '',
|
|
126
|
+
# Latex figure (float) alignment
|
|
127
|
+
#
|
|
128
|
+
# 'figure_align': 'htbp',
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Grouping the document tree into LaTeX files. List of tuples
|
|
132
|
+
# (source start file, target name, title, author, documentclass
|
|
133
|
+
# [howto, manual, or own class]).
|
|
134
|
+
latex_documents = [
|
|
135
|
+
(
|
|
136
|
+
"content/user/user_guide",
|
|
137
|
+
"user_manual.tex",
|
|
138
|
+
"{}: User Guide".format(project_title),
|
|
139
|
+
"Jacob Fahy",
|
|
140
|
+
"manual",
|
|
141
|
+
),
|
|
142
|
+
(
|
|
143
|
+
"content/user/atbd",
|
|
144
|
+
"atbd.tex",
|
|
145
|
+
"{}: Algorithm Theoretical Basis Document".format(project_title),
|
|
146
|
+
"Jacob Fahy",
|
|
147
|
+
"manual",
|
|
148
|
+
),
|
|
149
|
+
]
|
examples/run_example.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""example: read a Sentinel-2 L1C SAFE product and run S2-RUT."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import glob
|
|
5
|
+
import socket
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from eoio import read
|
|
9
|
+
from shapely import wkt
|
|
10
|
+
|
|
11
|
+
from s2_rut_python.interface import S2RUTTool
|
|
12
|
+
|
|
13
|
+
if (
|
|
14
|
+
socket.gethostname() == "lyon.npl.co.uk"
|
|
15
|
+
or socket.gethostname() == "leipzig.npl.co.uk"
|
|
16
|
+
or "leiden" in socket.gethostname()
|
|
17
|
+
):
|
|
18
|
+
DATA_DIRECTORY = "/mnt/t/data/"
|
|
19
|
+
else:
|
|
20
|
+
DATA_DIRECTORY = r"T:\ECO\EOServer\data"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Define input path from test datasets
|
|
24
|
+
SAFE_PATH = os.path.join(
|
|
25
|
+
DATA_DIRECTORY,
|
|
26
|
+
"unittest_datasets",
|
|
27
|
+
"S2MSIL1C",
|
|
28
|
+
"S2A_MSIL1C_20251128T111431_N0511_R137_T30UXE_20251128T121631.SAFE",
|
|
29
|
+
)
|
|
30
|
+
print("SAFE PATH:", SAFE_PATH)
|
|
31
|
+
|
|
32
|
+
# Define ROI
|
|
33
|
+
roi_string = "POLYGON ((\
|
|
34
|
+
-0.913910 53.786950,\
|
|
35
|
+
-0.382900 53.776490,\
|
|
36
|
+
-0.406240 53.464690,\
|
|
37
|
+
-0.925060 53.474770,\
|
|
38
|
+
-0.913910 53.786950\
|
|
39
|
+
))"
|
|
40
|
+
|
|
41
|
+
geom = wkt.loads(roi_string)
|
|
42
|
+
|
|
43
|
+
# Read the dataset with eoio, selecting only a few bands and auxiliary variables for efficiency.
|
|
44
|
+
bands = ["B01", "B03", "B09"]
|
|
45
|
+
ds = read(
|
|
46
|
+
SAFE_PATH,
|
|
47
|
+
vars_sel={
|
|
48
|
+
"meas": bands,
|
|
49
|
+
"aux": [
|
|
50
|
+
"solar_zenith_angle",
|
|
51
|
+
"solar_azimuth_angle",
|
|
52
|
+
"viewing_zenith_angle",
|
|
53
|
+
"viewing_azimuth_angle",
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
read_params={
|
|
57
|
+
"use_chunks": True,
|
|
58
|
+
"metadata_level": "all",
|
|
59
|
+
"save_extracted": True,
|
|
60
|
+
"ave_va_det": True,
|
|
61
|
+
},
|
|
62
|
+
subset={"roi": geom, "roi_crs": "EPSG:4326"},
|
|
63
|
+
processors={
|
|
64
|
+
"interpolate": {
|
|
65
|
+
"coords": ["y_5000m", "x_5000m"],
|
|
66
|
+
"data_vars": ["solar_zenith_angle"],
|
|
67
|
+
"target_grid": [["y_60m", "y_10m"], ["x_60m", "x_10m"]],
|
|
68
|
+
"method": "linear",
|
|
69
|
+
"inplace": False,
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Run S2-RUT on the dataset, computing both random and systematic uncertainties.
|
|
75
|
+
print("Running S2-RUT")
|
|
76
|
+
rut = S2RUTTool()
|
|
77
|
+
ds_out = rut.run(ds=ds, data_vars=bands, group_unc=True)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Create a single grid plot: rows = bands, columns = [reflectance, random [%], systematic [%]].
|
|
81
|
+
fig, axes = plt.subplots(
|
|
82
|
+
nrows=len(bands),
|
|
83
|
+
ncols=3,
|
|
84
|
+
figsize=(15, 4 * len(bands)),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Handle single band case (axes is 1D instead of 2D).
|
|
88
|
+
if len(bands) == 1:
|
|
89
|
+
axes = axes.reshape(1, -1)
|
|
90
|
+
|
|
91
|
+
for i, band in enumerate(bands):
|
|
92
|
+
# Column 0: Reflectance
|
|
93
|
+
ds_out[band].plot(ax=axes[i, 0], robust=True)
|
|
94
|
+
axes[i, 0].set_title(f"{band} Reflectance")
|
|
95
|
+
axes[i, 0].set_xlabel("")
|
|
96
|
+
axes[i, 0].set_ylabel("")
|
|
97
|
+
|
|
98
|
+
# Column 1: Random uncertainty [%]
|
|
99
|
+
random_unc_pct = 100.0 * ds_out[f"u_random_{band}"] / ds_out[band]
|
|
100
|
+
random_unc_pct.plot(ax=axes[i, 1], robust=True)
|
|
101
|
+
axes[i, 1].set_title(f"{band} Random Uncertainty [%]")
|
|
102
|
+
axes[i, 1].set_xlabel("")
|
|
103
|
+
axes[i, 1].set_ylabel("")
|
|
104
|
+
|
|
105
|
+
# Column 2: Systematic uncertainty [%]
|
|
106
|
+
sys_unc_pct = 100.0 * ds_out[f"u_systematic_{band}"] / ds_out[band]
|
|
107
|
+
sys_unc_pct.plot(ax=axes[i, 2], robust=True)
|
|
108
|
+
axes[i, 2].set_title(f"{band} Systematic Uncertainty [%]")
|
|
109
|
+
axes[i, 2].set_xlabel("")
|
|
110
|
+
axes[i, 2].set_ylabel("")
|
|
111
|
+
|
|
112
|
+
plt.tight_layout()
|
|
113
|
+
plt.savefig("s2rut_example.png")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
pass
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
import matplotlib
|
|
5
|
+
from eoio import read
|
|
6
|
+
|
|
7
|
+
import s2_rut_python._vendor # noqa: F401
|
|
8
|
+
|
|
9
|
+
from S2RUT import S2RUT_L1
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
this_directory = os.path.dirname(__file__)
|
|
14
|
+
|
|
15
|
+
file = os.path.abspath(
|
|
16
|
+
os.path.join(
|
|
17
|
+
os.path.dirname(this_directory),
|
|
18
|
+
"third-party",
|
|
19
|
+
"Data",
|
|
20
|
+
"S2A_MSIL1C_20210310T084801_N0500_R107_T33KWP_20230525T152740.SAFE",
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
# Open product using eoio
|
|
24
|
+
ds = read(
|
|
25
|
+
file,
|
|
26
|
+
vars_sel={
|
|
27
|
+
"meas": ["B01"], # Read only a few bands for efficiency
|
|
28
|
+
"aux": [
|
|
29
|
+
"solar_zenith_angle",
|
|
30
|
+
"solar_azimuth_angle",
|
|
31
|
+
"viewing_zenith_angle",
|
|
32
|
+
"viewing_azimuth_angle",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
read_params={
|
|
36
|
+
"use_chunks": False,
|
|
37
|
+
"metadata_level": "all",
|
|
38
|
+
"save_extracted": True,
|
|
39
|
+
"ave_va_det": True, # Average over the detector dimension for the angle variables
|
|
40
|
+
},
|
|
41
|
+
processors={
|
|
42
|
+
"interpolate": {
|
|
43
|
+
"coords": ["y_5000m", "x_5000m"],
|
|
44
|
+
"data_vars": ["solar_zenith_angle"],
|
|
45
|
+
"target_grid": ["y_60m", "x_60m"],
|
|
46
|
+
"method": "linear",
|
|
47
|
+
"inplace": True,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
print(ds.data_vars)
|
|
53
|
+
# print(ds['solar_zenith_angle'])
|
|
54
|
+
print(ds.coords)
|
|
55
|
+
|
|
56
|
+
# Compute uncertainty (absolute value, in reflectance dimension)
|
|
57
|
+
input_contributors = os.path.abspath(
|
|
58
|
+
os.path.join(
|
|
59
|
+
os.path.dirname(this_directory), "third-party", "Data", "unc_contributors.json"
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
metadata = {
|
|
64
|
+
"spacecraft": None,
|
|
65
|
+
"quant": None,
|
|
66
|
+
"A": [],
|
|
67
|
+
"offset": [],
|
|
68
|
+
"alpha": {},
|
|
69
|
+
"beta": {},
|
|
70
|
+
"Esun": [],
|
|
71
|
+
"Usun": None,
|
|
72
|
+
"refined": False,
|
|
73
|
+
} # this dictionary contains the relevant metadata parameters
|
|
74
|
+
# read required metadata from ds.attrs and fill the metadata dictionary
|
|
75
|
+
METADATA_MAP = {
|
|
76
|
+
"spacecraft": "platform",
|
|
77
|
+
"quant": "quantification_level",
|
|
78
|
+
"Usun": "reflectance_conversion_u",
|
|
79
|
+
}
|
|
80
|
+
VAR_MTD_MAP = {
|
|
81
|
+
"Esun": "solar_irradiance",
|
|
82
|
+
"alpha": "noise_model_alpha",
|
|
83
|
+
"beta": "noise_model_beta",
|
|
84
|
+
"A": "physical_gains",
|
|
85
|
+
"offset": "radiometric_offset",
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for key, path in METADATA_MAP.items():
|
|
89
|
+
if path in ds.attrs:
|
|
90
|
+
metadata[key] = ds.attrs[path]
|
|
91
|
+
elif path in ds.attrs["product_metadata"]:
|
|
92
|
+
metadata[key] = ds.attrs["product_metadata"][path]
|
|
93
|
+
else:
|
|
94
|
+
raise KeyError(
|
|
95
|
+
f"Required metadata parameter '{key}' not found in dataset attributes at path '{path}'."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
for key, path in VAR_MTD_MAP.items():
|
|
99
|
+
metadata[key] = {
|
|
100
|
+
band: ds[band].attrs["product_metadata"][path]
|
|
101
|
+
for band in ds.data_vars
|
|
102
|
+
if "B" in band
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
print("Metadata extracted for uncertainty calculation:", metadata)
|
|
106
|
+
RUTl1 = S2RUT_L1(input_contributors)
|
|
107
|
+
u_ref, u_cont = RUTl1.unc_calculation_abs(
|
|
108
|
+
ds["B01"].values,
|
|
109
|
+
"B01",
|
|
110
|
+
0,
|
|
111
|
+
metadata,
|
|
112
|
+
[ds["solar_zenith_angle"].values],
|
|
113
|
+
do_contributor=True,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
print("Uncertainty calculated for B01:", u_ref, u_cont)
|
|
118
|
+
print("Shape of u_ref:", u_ref.shape)
|
|
119
|
+
print("u_cont keys:", u_cont.keys())
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
from s2_rut_python.interface import S2RUTTool
|
|
123
|
+
|
|
124
|
+
rut_processor = S2RUTTool()
|
|
125
|
+
ds = rut_processor.run(
|
|
126
|
+
ds,
|
|
127
|
+
data_vars=["B01"],
|
|
128
|
+
group_unc=False, # set to True to compute group uncertainties (systematic and random)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Check the resulting dataset
|
|
132
|
+
print("Data variables in resulting dataset:", ds.data_vars)
|
|
133
|
+
print(ds.unc)
|
|
134
|
+
|
|
135
|
+
# compare with reference uncertainty
|
|
136
|
+
import matplotlib.pyplot as plt
|
|
137
|
+
|
|
138
|
+
# plt.imshow(ds.B01.values)
|
|
139
|
+
# plt.title("B01 reflectance")
|
|
140
|
+
# plt.colorbar()
|
|
141
|
+
# plt.show()
|
|
142
|
+
# for unc in ds.data_vars:
|
|
143
|
+
# if 'u_' in unc:
|
|
144
|
+
# print(f"Comparing {unc} with reference uncertainty...")
|
|
145
|
+
# if unc.split('_B01')[0] in u_cont:
|
|
146
|
+
# plt.imshow(ds[unc].values - u_cont[unc.split('_B01')[0]])
|
|
147
|
+
# plt.title(f"Difference between {unc} and reference uncertainty")
|
|
148
|
+
# plt.colorbar()
|
|
149
|
+
# plt.show()
|
|
150
|
+
|
|
151
|
+
ds = read(
|
|
152
|
+
file,
|
|
153
|
+
vars_sel={
|
|
154
|
+
"meas": ["B01"], # Read only a few bands for efficiency
|
|
155
|
+
"aux": [
|
|
156
|
+
"solar_zenith_angle",
|
|
157
|
+
"solar_azimuth_angle",
|
|
158
|
+
"viewing_zenith_angle",
|
|
159
|
+
"viewing_azimuth_angle",
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
read_params={
|
|
163
|
+
"use_chunks": False,
|
|
164
|
+
"metadata_level": "all",
|
|
165
|
+
"save_extracted": True,
|
|
166
|
+
"ave_va_det": True, # Average over the detector dimension for the angle variables
|
|
167
|
+
},
|
|
168
|
+
processors={
|
|
169
|
+
"interpolate": {
|
|
170
|
+
"coords": ["y_5000m", "x_5000m"],
|
|
171
|
+
"data_vars": ["solar_zenith_angle"],
|
|
172
|
+
"target_grid": ["y_60m", "x_60m"],
|
|
173
|
+
"method": "linear",
|
|
174
|
+
"inplace": True,
|
|
175
|
+
},
|
|
176
|
+
"s2_rut": {
|
|
177
|
+
"data_vars": ["B01"],
|
|
178
|
+
"group_unc": True, # set to True to compute group uncertainties (systematic and random)
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
print("Data variables in resulting dataset after s2_rut processor:", ds.data_vars)
|
|
184
|
+
print(ds.unc)
|
|
185
|
+
|
|
186
|
+
for unc in ds.data_vars:
|
|
187
|
+
if "u_" in unc:
|
|
188
|
+
print(f"Comparing {unc} with reference uncertainty...")
|
|
189
|
+
if unc.split("_B01")[0] in u_cont:
|
|
190
|
+
plt.imshow(ds[unc].values - u_cont[unc.split("_B01")[0]])
|
|
191
|
+
plt.title(f"Difference between {unc} and reference uncertainty")
|
|
192
|
+
plt.colorbar()
|
|
193
|
+
plt.show()
|
|
194
|
+
else:
|
|
195
|
+
import numpy as np
|
|
196
|
+
|
|
197
|
+
(100 * ds[unc] / ds["B01"]).plot(
|
|
198
|
+
robust=True
|
|
199
|
+
) # , vmin=np.nanpercentile(100*ds[unc].values / ds['B01'].values, 1), vmax=np.nanpercentile(100*ds[unc].values / ds['B01'].values, 99)) # relative uncertainty in percentage
|
|
200
|
+
plt.title(f"{unc} (no reference uncertainty available)")
|
|
201
|
+
# plt.colorbar()
|
|
202
|
+
plt.show()
|
s2_rut_python/_vendor.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Internal helper to make vendored third-party S2-RUT code importable.
|
|
3
|
+
|
|
4
|
+
This module adjusts sys.path to include the vendored subtree.
|
|
5
|
+
Do not modify without updating the subtree integration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
_BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
|
12
|
+
_VENDOR_DIR = os.path.join(
|
|
13
|
+
_BASE_DIR,
|
|
14
|
+
"third-party",
|
|
15
|
+
"Source",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
if _VENDOR_DIR not in sys.path:
|
|
19
|
+
sys.path.insert(0, _VENDOR_DIR)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.29) from
|
|
3
|
+
# revision-control system data, or from the parent directory name of an
|
|
4
|
+
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
+
# of this file.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
version_json = '''
|
|
10
|
+
{
|
|
11
|
+
"date": "2026-04-11T21:23:36+0100",
|
|
12
|
+
"dirty": false,
|
|
13
|
+
"error": null,
|
|
14
|
+
"full-revisionid": "53f4b6263d29cba0b31d24f7520fab6bd921c56a",
|
|
15
|
+
"version": "0.0.1"
|
|
16
|
+
}
|
|
17
|
+
''' # END VERSION_JSON
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_versions():
|
|
21
|
+
return json.loads(version_json)
|