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 QLFlareFlag product and fix attr description #125

Merged
merged 10 commits into from
Jun 17, 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
6 changes: 1 addition & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,19 @@ jobs:
core:
uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1
with:
coverage: codecov
envs: |
- linux: codestyle
- linux: py39
coverage: 'codecov'
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

test:
needs: [core]
uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1
with:
coverage: codecov
envs: |
- macos: py39
- windows: py39
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

doc:
needs: [test]
Expand Down
1 change: 1 addition & 0 deletions changelog/125.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add missing QL products `~stixpy.product.sources.quicklook.QLVariance`, `~stixpy.product.sources.quicklook.QLFlareFlag`, and `~stixpy.product.sources.quicklook.QLTMStatusFlareList` to Product. Also added some useful properties to the for status words.
1 change: 0 additions & 1 deletion stixpy/coordinates/tests/test_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from sunpy.map.mapbase import SpatialPair

from stixpy.coordinates.frames import STIXImaging, stix_frame_to_wcs, stix_wcs_to_frame
from stixpy.coordinates.transforms import hpc_to_stixim, stixim_to_hpc # noqa
from stixpy.map.stix import STIXMap


Expand Down
3 changes: 2 additions & 1 deletion stixpy/net/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ def register_values(cls):
("ql_variance", "Quick look variance curve"),
("ql_spectra", "Quick look spectra"),
("ql_calibration_spectrum", "Quick look energy " "calibration spectrum"),
("ql_flareflag", "Quick look energy calibration spectrum"),
("ql_flareflag", "Quick look flare flag including location"),
("ql_tmstatusflarelist", "Quick look TM Status and flare list"),
("sci_xray_rpd", "Raw Pixel Data"),
("sci_xray_cpd", "Compressed Pixel Data"),
("sci_xray_scpd", "Summed Compressed Pixel Data"),
Expand Down
6 changes: 3 additions & 3 deletions stixpy/net/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def test_client(urlopen, client, http_response, time_range, nfiles):
@pytest.mark.remote_data
def test_search_date(client):
res = client.search(a.Time("2020-05-01T00:00", "2020-05-01T23:59"), a.Instrument.stix)
assert len(res) == 37
assert len(res) == 38


@pytest.mark.remote_data
Expand Down Expand Up @@ -86,10 +86,10 @@ def test_search_date_product_sci():
@pytest.mark.remote_data
def test_fido():
res = Fido.search(a.Time("2020-11-17T00:00", "2020-11-17T23:59"), a.Instrument.stix)
assert len(res["stix"]) == 50
assert len(res["stix"]) == 51

res_ql = Fido.search(a.Time("2020-11-17T00:00", "2020-11-17T23:59"), a.Instrument.stix, a.stix.DataType.ql)
assert len(res_ql["stix"]) == 5
assert len(res_ql["stix"]) == 6

res_sci = Fido.search(a.Time("2020-11-17T00:00", "2020-11-17T23:59"), a.Instrument.stix, a.stix.DataType.sci)
assert len(res_sci["stix"]) == 42
13 changes: 11 additions & 2 deletions stixpy/product/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,23 @@ def level(self):

@property
def service_type(self):
r"""
Service type
"""
return self.meta.get("stype")

@property
def servie_subtype(self):
def service_subtype(self):
r"""
Service subtype
"""
return self.meta.get("stype")

@property
def ssid(self):
def ssid(self) -> int:
r"""
Science Structure ID for product
"""
return self.meta.get("ssid")


Expand Down
134 changes: 127 additions & 7 deletions stixpy/product/sources/quicklook.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
import astropy.units as u
import numpy as np
from astropy.coordinates import SkyCoord
from astropy.time import Time
from astropy.units import Quantity
from numpy.typing import NDArray
from sunpy.time import TimeRange

from stixpy.coordinates.frames import STIXImaging
from stixpy.product.product import L1Product

__all__ = ["QuickLookProduct", "QLLightCurve", "QLBackground"]
THERMAL_INDEX_MAP = np.array(["None", "Minor", "Small", "Moderate", "Major"])
FLUX_INDEX_MAP = np.array(["None", "Weak", "Significant"])
LOCATION_INDEX_MAP = np.array(["None", "Previous", "New"])
TM_PROCESSING_STATUS = {
0x01: "Imaging Started",
0x02: "Imaging Ended",
0x04: "Spectroscopy Started",
0x08: "Spectroscopy Ended",
0x10: "Publication Started",
0x20: "Publication Ended",
0x40: "Cancelled",
0x80: "New Entry",
}

__all__ = ["QuickLookProduct", "QLLightCurve", "QLBackground", "QLVariance", "QLFlareFlag", "QLLightCurve"]


class QuickLookProduct(L1Product):
Expand All @@ -11,13 +32,19 @@ class QuickLookProduct(L1Product):
"""

@property
def time_range(self):
def time(self) -> Time:
return self.data["time"]

@property
def exposure_time(self) -> Quantity[u.s]:
return self.data["timedel"].to(u.s)

@property
def time_range(self) -> TimeRange:
"""
A `sunpy.time.TimeRange` for the data.
"""
return TimeRange(
self.data["time"][0] - self.data["timedel"][0] / 2, self.data["time"][-1] + self.data["timedel"][-1] / 2
)
return TimeRange(self.time[0] - self.exposure_time[0] / 2, self.time[-1] + self.exposure_time[-1] / 2)


class QLLightCurve(QuickLookProduct):
Expand All @@ -27,7 +54,7 @@ class QLLightCurve(QuickLookProduct):

@classmethod
def is_datasource_for(cls, *, meta, **kwargs):
"""Determines if meta data meach Raw Pixel Data"""
"""Determines if meta data match"""
service_subservice_ssid = tuple(meta[name] for name in ["STYPE", "SSTYPE", "SSID"])
level = meta["level"]
if service_subservice_ssid == (21, 6, 30) and level == "L1":
Expand All @@ -44,11 +71,104 @@ class QLBackground(QuickLookProduct):

@classmethod
def is_datasource_for(cls, *, meta, **kwargs):
"""Determines if meta data meach Raw Pixel Data"""
"""Determines if meta data match"""
service_subservice_ssid = tuple(meta[name] for name in ["STYPE", "SSTYPE", "SSID"])
level = meta["level"]
if service_subservice_ssid == (21, 6, 31) and level == "L1":
return True

def __repr__(self):
return f"{self.__class__.__name__}\n" f" {self.time_range}"


class QLVariance(QuickLookProduct):
"""
Quicklook variance nominally in 5 energy bins every 8s
"""

@classmethod
def is_datasource_for(cls, *, meta, **kwargs):
"""Determines if meta data match"""
service_subservice_ssid = tuple(meta[name] for name in ["STYPE", "SSTYPE", "SSID"])
level = meta["level"]
if service_subservice_ssid == (21, 6, 33) and level == "L1":
return True

def __repr__(self):
return f"{self.__class__.__name__}\n" f" {self.time_range}"


class QLFlareFlag(QuickLookProduct):
"""
Quicklook Flare flag and location
"""

@classmethod
def is_datasource_for(cls, *, meta, **kwargs):
"""Determines if meta data match"""
service_subservice_ssid = tuple(meta[name] for name in ["STYPE", "SSTYPE", "SSID"])
level = meta["level"]
if service_subservice_ssid == (21, 6, 34) and level == "L1":
return True

@property
def thermal_index(self):
r"""
Flare thermal index - amount of thermal emission
"""
return THERMAL_INDEX_MAP[self.data["thermal_index"]]

@property
def flare_location(self) -> SkyCoord:
r"""
Flare location as`

Notes
-----
From STIX-TN-0109-FHNW_I3R3 `YLOS = -Ysc = -Yint` and `ZLOS = Zsc = Xint`

"""
return SkyCoord(
self.data["loc_z"] * u.arcmin, -self.data["loc_y"] * u.arcmin, frame=STIXImaging(obstime=self.data["time"])
)

@property
def non_thermal_index(self) -> NDArray[str]:
r"""
Flare non-thermal index - significant non-thermal emission
"""
return THERMAL_INDEX_MAP[self.data["non_thermal_index"]]

@property
def location_flag(self) -> NDArray[str]:
r"""
Flare location flag
"""
return THERMAL_INDEX_MAP[self.data["location_status"]]

def __repr__(self):
return f"{self.__class__.__name__}\n" f" {self.time_range}"


class QLTMStatusFlareList(QuickLookProduct):
"""
Quicklook variance nominally in 5 energy bins every 8s
"""

@classmethod
def is_datasource_for(cls, *, meta, **kwargs):
"""Determines if meta data match"""
service_subservice_ssid = tuple(meta[name] for name in ["STYPE", "SSTYPE", "SSID"])
level = meta["level"]
if service_subservice_ssid == (21, 6, 43) and level == "L1":
return True

@property
def processing_status(self):
r"""
Processing status
"""
return [TM_PROCESSING_STATUS[status] for status in self.data["processing_mask"]]

def __repr__(self):
return f"{self.__class__.__name__}\n" f" {self.time_range}"
18 changes: 18 additions & 0 deletions stixpy/product/sources/tests/test_quicklook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest
from astropy.coordinates import SkyCoord

from stixpy.product import Product
from stixpy.product.sources import QLFlareFlag


@pytest.mark.remote_data
def test_qlflareflag():
ff = Product(
"https://pub099.cs.technik.fhnw.ch/fits/L1/2024/06/03/QL/" "solo_L1_stix-ql-flareflag_20240603_V02U.fits"
)
assert isinstance(ff, QLFlareFlag)
assert isinstance(ff.flare_location, SkyCoord)
assert ff.flare_location[0].transform_to(frame="helioprojective").frame.name == "helioprojective"
assert ff.location_flag[0, 0] == "None"
assert ff.thermal_index[0, 0] == "Minor"
assert ff.non_thermal_index[0, 0] == "None"
Loading