diff --git a/changelog.d/20241216_192656_steliosvoutsinas_DM_46975.md b/changelog.d/20241216_192656_steliosvoutsinas_DM_46975.md
new file mode 100644
index 0000000..98d3905
--- /dev/null
+++ b/changelog.d/20241216_192656_steliosvoutsinas_DM_46975.md
@@ -0,0 +1,6 @@
+
+
+### New features
+
+- Now reads bands information from obscore config
+- Fix some of the self-descirption documentation (calibs and remove specify statements)
diff --git a/src/sia/models/sia_query_params.py b/src/sia/models/sia_query_params.py
index 4f48034..0da7bfc 100644
--- a/src/sia/models/sia_query_params.py
+++ b/src/sia/models/sia_query_params.py
@@ -14,6 +14,7 @@
from ..models.common import CaseInsensitiveEnum
__all__ = [
+ "BandInfo",
"BaseQueryParams",
"CalibLevel",
"DPType",
@@ -66,6 +67,48 @@ class Polarization(CaseInsensitiveEnum):
YX = "YX"
+@dataclass
+class BandInfo:
+ """A class to represent a band's wavelength range.
+
+ Attributes
+ ----------
+ label
+ The band's label.
+ low
+ The low end of the band's wavelength range.
+ high
+ The high end of the band's wavelength range.
+ """
+
+ label: str
+ low: float
+ high: float
+
+ @property
+ def midpoint(self) -> float:
+ """Calculate the midpoint of the band's wavelength range.
+
+ Returns
+ -------
+ float
+ The midpoint of the band's wavelength range
+ """
+ return (self.low + self.high) / 2
+
+ @property
+ def formatted_midpoint(self) -> str:
+ """Return the midpoint formatted in scientific notation.
+
+ Returns
+ -------
+ str
+ The midpoint formatted in scientific notation
+ """
+ nm_value = self.midpoint * 1e9
+ return f"{nm_value:.1f}e-9"
+
+
class BaseQueryParams(ABC):
"""Base class for query parameters."""
diff --git a/src/sia/services/response_handler.py b/src/sia/services/response_handler.py
index 9918120..ce0cd3f 100644
--- a/src/sia/services/response_handler.py
+++ b/src/sia/services/response_handler.py
@@ -16,6 +16,7 @@
from ..constants import RESULT_NAME as RESULT
from ..factory import Factory
from ..models.data_collections import ButlerDataCollection
+from ..models.sia_query_params import BandInfo
from ..services.votable import VotableConverterService
logger = structlog.get_logger(__name__)
@@ -32,6 +33,34 @@
class ResponseHandlerService:
"""Service for handling the SIAv2 query response."""
+ @staticmethod
+ def _generate_band_info(
+ spectral_ranges: dict[str, tuple[float | None, float | None]],
+ ) -> list[BandInfo]:
+ """Generate band information from spectral ranges dictionary.
+
+ Parameters
+ ----------
+ spectral_ranges
+ The spectral ranges dictionary.
+
+ Returns
+ -------
+ list[BandInfo]
+ The list of BandInfo objects.
+ """
+ bands = []
+ for band_name, (low, high) in spectral_ranges.items():
+ if low is not None and high is not None:
+ # The Rubin label is hardcoded here, but it could be
+ # parameterized if needed in the future.
+ bands.append(
+ BandInfo(
+ label=f"Rubin band {band_name}", low=low, high=high
+ )
+ )
+ return bands
+
@staticmethod
def self_description_response(
request: Request,
@@ -59,6 +88,10 @@ def self_description_response(
Response
The response containing the self-description.
"""
+ bands = ResponseHandlerService._generate_band_info(
+ obscore_config.spectral_ranges
+ )
+
return _TEMPLATES.TemplateResponse(
request,
"self_description.xml",
@@ -77,6 +110,7 @@ def self_description_response(
"query", collection_name=butler_collection.name
),
"facility_name": obscore_config.facility_name.strip(),
+ "bands": bands,
},
headers={
"content-disposition": f"attachment; filename={RESULT}.xml",
diff --git a/src/sia/templates/self_description.xml b/src/sia/templates/self_description.xml
index 99702ac..793ad4f 100644
--- a/src/sia/templates/self_description.xml
+++ b/src/sia/templates/self_description.xml
@@ -5,16 +5,18 @@
Self description and list of supported parameters
-
- Energy bounds
+
+ Wavelength/filter band selection
+ {%- for band in bands %}
+
+ {%- endfor %}
Calibration level
-
-
-
-
+
+
+
@@ -81,10 +83,10 @@
- Specify position resolution
+ Position resolution
- Specify energy resolving power
+ Energy resolving power
Target name
@@ -121,7 +123,7 @@
Product type (e.g. science, calibration, auxiliary, preview, info)
- Calibration level of the observation: in {0, 1, 2, 3, 4}
+ Calibration level of the observation: in {1, 2, 3}
Data product (file content) primary type
@@ -198,4 +200,4 @@
-
\ No newline at end of file
+
diff --git a/tests/handlers/external/external_test.py b/tests/handlers/external/external_test.py
index d79aaec..ba362f8 100644
--- a/tests/handlers/external/external_test.py
+++ b/tests/handlers/external/external_test.py
@@ -12,6 +12,7 @@
from sia.config import config
from sia.constants import RESULT_NAME
+from sia.models.sia_query_params import BandInfo
from tests.support.butler import MockButler, MockButlerQueryService
from tests.support.constants import EXCEPTION_MESSAGES
from tests.support.validators import validate_votable_error
@@ -240,12 +241,29 @@ async def test_query_maxrec_zero(
)
templates_dir = Jinja2Templates(template_dir)
+ bands = [
+ BandInfo(label="Rubin band HSC-G", low=406.0e-9, high=545.0e-9),
+ BandInfo(label="Rubin band HSC-R", low=543.0e-9, high=693.0e-9),
+ BandInfo(label="Rubin band HSC-R2", low=542.0e-9, high=693.0e-9),
+ BandInfo(label="Rubin band HSC-I", low=690.0e-9, high=842.0e-9),
+ BandInfo(label="Rubin band HSC-I2", low=692.0e-9, high=850.0e-9),
+ BandInfo(label="Rubin band HSC-Z", low=852.0e-9, high=928.0e-9),
+ BandInfo(label="Rubin band HSC-Y", low=937.0e-9, high=1015.0e-9),
+ BandInfo(label="Rubin band N921", low=914.7e-9, high=928.1e-9),
+ BandInfo(label="Rubin band g", low=406.0e-9, high=545.0e-9),
+ BandInfo(label="Rubin band r", low=542.0e-9, high=693.0e-9),
+ BandInfo(label="Rubin band i", low=692.0e-9, high=850.0e-9),
+ BandInfo(label="Rubin band z", low=852.0e-9, high=928.0e-9),
+ BandInfo(label="Rubin band y", low=937.0e-9, high=1015.0e-9),
+ ]
+
context = {
"instruments": ["HSC"],
"collections": ["LSST.CI"],
"resource_identifier": "ivo://rubin//ci_hsc_gen3",
"access_url": "https://example.com/api/sia/hsc/query",
"facility_name": "Subaru",
+ "bands": bands,
}
template_rendered = templates_dir.get_template(
diff --git a/tests/models/sia_params_test.py b/tests/models/sia_params_test.py
index b4ec4cb..a357980 100644
--- a/tests/models/sia_params_test.py
+++ b/tests/models/sia_params_test.py
@@ -6,6 +6,7 @@
from sia.models.common import CaseInsensitiveEnum
from sia.models.sia_query_params import (
+ BandInfo,
CalibLevel,
DPType,
Polarization,
@@ -135,6 +136,64 @@ async def test_sia_params_default_values() -> None:
assert params.responseformat is None
+def test_band_info_initialization() -> None:
+ """Test proper initialization of BandInfo."""
+ band = BandInfo(label="Rubin band u", low=330.0e-9, high=400.0e-9)
+ assert band.label == "Rubin band u"
+ assert band.low == 330.0e-9
+ assert band.high == 400.0e-9
+
+
+def test_band_info_midpoint_calculation() -> None:
+ """Test midpoint calculations for different bands."""
+ band_u = BandInfo(label="Rubin band u", low=330.0e-9, high=400.0e-9)
+ expected_u_midpoint = (330.0e-9 + 400.0e-9) / 2
+ assert band_u.midpoint == expected_u_midpoint
+
+ band_y = BandInfo(label="Rubin band y", low=970.0e-9, high=1060.0e-9)
+ expected_y_midpoint = (970.0e-9 + 1060.0e-9) / 2
+ assert band_y.midpoint == expected_y_midpoint
+
+
+def test_band_info_formatted_midpoint() -> None:
+ """Test formatted midpoint string representations."""
+ test_cases = [
+ {
+ "label": "Rubin band u",
+ "low": 330.0e-9,
+ "high": 400.0e-9,
+ "expected": "365.0e-9",
+ },
+ {
+ "label": "Rubin band g",
+ "low": 402.0e-9,
+ "high": 552.0e-9,
+ "expected": "477.0e-9",
+ },
+ {
+ "label": "Rubin band y",
+ "low": 970.0e-9,
+ "high": 1060.0e-9,
+ "expected": "1015.0e-9",
+ },
+ ]
+
+ for case in test_cases:
+ low = (
+ float(case["low"])
+ if isinstance(case["low"], (int | float))
+ else 0.0
+ )
+ high = (
+ float(case["high"])
+ if isinstance(case["high"], (int | float))
+ else 0.0
+ )
+
+ band = BandInfo(label=str(case["label"]), low=low, high=high)
+ assert band.formatted_midpoint == case["expected"]
+
+
@pytest.fixture
def sample_sia_params() -> SIAQueryParams:
return SIAQueryParams(
diff --git a/tests/templates/self_description.xml b/tests/templates/self_description.xml
index 99702ac..793ad4f 100644
--- a/tests/templates/self_description.xml
+++ b/tests/templates/self_description.xml
@@ -5,16 +5,18 @@
Self description and list of supported parameters
-
- Energy bounds
+
+ Wavelength/filter band selection
+ {%- for band in bands %}
+
+ {%- endfor %}
Calibration level
-
-
-
-
+
+
+
@@ -81,10 +83,10 @@
- Specify position resolution
+ Position resolution
- Specify energy resolving power
+ Energy resolving power
Target name
@@ -121,7 +123,7 @@
Product type (e.g. science, calibration, auxiliary, preview, info)
- Calibration level of the observation: in {0, 1, 2, 3, 4}
+ Calibration level of the observation: in {1, 2, 3}
Data product (file content) primary type
@@ -198,4 +200,4 @@
-
\ No newline at end of file
+