Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Sentinel-2C #234

Merged
merged 7 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/platforms_supported.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ have been included in Pyspectral.
* - Sentinel-2B msi
- `rsr_msi_Sentinel-2B.h5`
- ESA-Sentinel-MSI_
* - Sentinel-2C msi
- `rsr_msi_Sentinel-2C.h5`
- ESA-Sentinel-MSI_
* - NOAA-20 viirs
- `rsr_viirs_NOAA-20.h5`
- NESDIS_
Expand Down
10 changes: 6 additions & 4 deletions pyspectral/etc/pyspectral.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,12 @@ download_from_internet: True
# Arctica-M-N1-msu-gsa:
# path: /path/to/original/Arctica_M_N1_SRF.xlsx

# Sentinel-2A-msi:
# path: /path/to/original/sentinel-2a/msi/data/S2-SRF_COPE-GSEG-EOPG-TN-15-0007_3.0.xlsx
# Sentinel-2B-msi:
# path: /path/to/original/sentinel-2b/msi/data/S2-SRF_COPE-GSEG-EOPG-TN-15-0007_3.0.xlsx
#Sentinel-2A-msi:
# path: /path/to/COPE-GSEG-EOPG-TN-15-0007-Sentinel-2_Spectral_Response_Functions_2024-4.0.xlsx
#Sentinel-2B-msi:
# path: /path/to/COPE-GSEG-EOPG-TN-15-0007-Sentinel-2_Spectral_Response_Functions_2024-4.0.xlsx
#Sentinel-2C-msi:
# path: /path/to/COPE-GSEG-EOPG-TN-15-0007-Sentinel-2_Spectral_Response_Functions_2024-4.0.xlsx

# Himawari-8-ahi:
# path: /path/to/original/ahi/data
Expand Down
6 changes: 4 additions & 2 deletions pyspectral/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
'EOS-Terra': 'modis',
'Sentinel-2A': 'msi',
'Sentinel-2B': 'msi',
'Sentinel-2C': 'msi',
'Arctica-M-N1': 'msu-gsa',
'Electro-L-N2': 'msu-gs',
'Sentinel-3A': ['olci', 'slstr'],
Expand All @@ -107,10 +108,11 @@
'avhrr-2': 'avhrr/2',
'avhrr-3': 'avhrr/3'}

HTTP_PYSPECTRAL_RSR = "https://zenodo.org/records/12743289/files/pyspectral_rsr_data.tgz"
HTTP_PYSPECTRAL_RSR = "https://zenodo.org/records/13833977/files/pyspectral_rsr_data.tgz"

RSR_DATA_VERSION_FILENAME = "PYSPECTRAL_RSR_VERSION"
RSR_DATA_VERSION = "v1.3.2"
RSR_DATA_VERSION = "v1.4.0"


ATM_CORRECTION_LUT_VERSION = {}
ATM_CORRECTION_LUT_VERSION['antarctic_aerosol'] = {'version': 'v1.0.1',
Expand Down
4 changes: 2 additions & 2 deletions rsr_convert_scripts/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ Terra files have names like this: ``rsr.1.oobd.det``

%> python msi_reader.py

The original Sentinel-2 A&B MSI spectral responses. Filenames look like this
``S2-SRF_COPE-GSEG-EOPG-TN-15-0007_3.0.xlsx``
The original Sentinel-2 A,B, and C MSI spectral responses. Filenames look like this
``COPE-GSEG-EOPG-TN-15-0007-Sentinel-2_Spectral_Response_Functions_2024-4.0.xlsx``

.. code::

Expand Down
117 changes: 41 additions & 76 deletions rsr_convert_scripts/msi_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,47 +29,34 @@
import os

import numpy as np
from xlrd import open_workbook
import pandas as pd

from pyspectral.raw_reader import InstrumentRSR
from pyspectral.utils import convert2hdf5 as tohdf5

LOG = logging.getLogger(__name__)


MSI_BAND_NAMES = {}
MSI_BAND_NAMES['S2A'] = {'S2A_SR_AV_B1': 'B01',
'S2A_SR_AV_B2': 'B02',
'S2A_SR_AV_B3': 'B03',
'S2A_SR_AV_B4': 'B04',
'S2A_SR_AV_B5': 'B05',
'S2A_SR_AV_B6': 'B06',
'S2A_SR_AV_B7': 'B07',
'S2A_SR_AV_B8': 'B08',
'S2A_SR_AV_B8A': 'B8A',
'S2A_SR_AV_B9': 'B09',
'S2A_SR_AV_B10': 'B10',
'S2A_SR_AV_B11': 'B11',
'S2A_SR_AV_B12': 'B12'}
MSI_BAND_NAMES['S2B'] = {'S2B_SR_AV_B1': 'B01',
'S2B_SR_AV_B2': 'B02',
'S2B_SR_AV_B3': 'B03',
'S2B_SR_AV_B4': 'B04',
'S2B_SR_AV_B5': 'B05',
'S2B_SR_AV_B6': 'B06',
'S2B_SR_AV_B7': 'B07',
'S2B_SR_AV_B8': 'B08',
'S2B_SR_AV_B8A': 'B8A',
'S2B_SR_AV_B9': 'B09',
'S2B_SR_AV_B10': 'B10',
'S2B_SR_AV_B11': 'B11',
'S2B_SR_AV_B12': 'B12'}

SHEET_HEADERS = {'Spectral Responses (S2A)': 'S2A',
'Spectral Responses (S2B)': 'S2B'}

PLATFORM_SHORT_NAME = {'Sentinel-2A': 'S2A',
'Sentinel-2B': 'S2B'}
MSI_BAND_NAMES = {"B01": "B1",
"B02": "B2",
"B03": "B3",
"B04": "B4",
"B05": "B5",
"B06": "B6",
"B07": "B7",
"B08": "B8",
"B8A": "B8A",
"B09": "B9",
"B10": "B10",
"B11": "B11",
"B12": "B12"}

SHEET_HEADERS = {"S2A": "Spectral Responses (S2A)",
"S2B": "Spectral Responses (S2B)",
"S2C": "Spectral Responses (S2C)"}

PLATFORM_SHORT_NAME = {"Sentinel-2A": "S2A",
"Sentinel-2B": "S2B",
"Sentinel-2C": "S2C"}


class MsiRSR(InstrumentRSR):
Expand All @@ -79,56 +66,34 @@ def __init__(self, bandname, platform_name):
"""Read the Sentinel-2 MSI relative spectral responses for all channels."""
super(MsiRSR, self).__init__(bandname, platform_name)

self.instrument = 'msi'
self.instrument = "msi"
self.platform_name = platform_name
self.short_plat = PLATFORM_SHORT_NAME[platform_name]
self._get_options_from_config()

LOG.debug("Filename: %s", str(self.path))
LOG.debug(f"Filename: {self.path}")
if os.path.exists(self.path):
self._load()
self._load(platform_name)
else:
raise IOError("Couldn't find an existing file for this band: " +
str(self.bandname))
raise IOError(f"Couldn't find an existing file for this band: {str(self.bandname)}")

def _load(self, scale=0.001):
"""Load the Sentinel-2 MSI relative spectral responses."""
with open_workbook(self.path) as wb_:
for sheet in wb_.sheets():
if sheet.name not in SHEET_HEADERS.keys():
continue

plt_short_name = PLATFORM_SHORT_NAME.get(self.platform_name)
if plt_short_name != SHEET_HEADERS.get(sheet.name):
continue

wvl = sheet.col_values(0, 1)
for idx in range(1, sheet.row_len(0)):
ch_name = MSI_BAND_NAMES[plt_short_name].get(str(sheet.col_values(idx, 0, 1)[0]))
if ch_name != self.bandname:
continue
bname = MSI_BAND_NAMES.get(self.bandname)
df = pd.read_excel(self.path, engine='openpyxl', sheet_name=SHEET_HEADERS[self.short_plat])
wvl = np.array(df['SR_WL'])
resp = np.array(df[f"{self.short_plat}_SR_AV_{bname}"])

resp = sheet.col_values(idx, 1)
resp = np.array(resp)
resp = np.where(resp == '', 0, resp).astype('float32')
mask = np.less_equal(resp, 0.00001)
wvl0 = np.ma.masked_array(wvl, mask=mask)
wvl_mask = np.ma.masked_outside(wvl, wvl0.min() - 2, wvl0.max() + 2)
mask = np.less_equal(resp, 0.00001)
wvl0 = np.ma.masked_array(wvl, mask=mask)
wvl_mask = np.ma.masked_outside(wvl, wvl0.min() - 2, wvl0.max() + 2)

wvl = wvl_mask.compressed()
resp = np.ma.masked_array(resp, mask=wvl_mask.mask).compressed()
self.rsr = {'wavelength': wvl / 1000., 'response': resp}

break

break
wvl = wvl_mask.compressed()
resp = np.ma.masked_array(resp, mask=wvl_mask.mask).compressed()
self.rsr = {"wavelength": wvl / 1000., "response": resp}


if __name__ == "__main__":
bands = MSI_BAND_NAMES['S2A'].values()
bands.sort()
for platform_name in ['Sentinel-2A', ]:
tohdf5(MsiRSR, platform_name, bands)

bands = MSI_BAND_NAMES['S2B'].values()
bands.sort()
for platform_name in ['Sentinel-2B', ]:
tohdf5(MsiRSR, platform_name, bands)

for plat_name in ["Sentinel-2A", "Sentinel-2B", "Sentinel-2C"]:
tohdf5(MsiRSR, plat_name, sorted(MSI_BAND_NAMES))
Loading