-
-
Notifications
You must be signed in to change notification settings - Fork 573
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
Providing a way to create and validate Solarnet-net compatible FITS headers #7271
base: main
Are you sure you want to change the base?
Changes from all commits
008ac5a
6c62a4d
0288492
662b806
b0a37a0
8e0d96a
f79bad9
d91b09d
ecd4cf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
.. _sunpy-topic-guide-fits-keywords: | ||
|
||
************************************ | ||
Creating and validating FITS Headers | ||
************************************ | ||
|
||
Sometimes it is necessary to inspect, validate, or create metadata for a FITS file. | ||
There are a number of standards and requirements associated with the keywords used in FITS files. | ||
When opening reading a FITS file, sunpy makes use of these standards to properly interpret the FITS metadata. | ||
|
||
The SOLARNET Metadata Recommendations for Solar Observations (Version 2.0, 14. August 2023) `https://arxiv.org/pdf/2011.12139.pdf <https://arxiv.org/pdf/2011.12139.pdf>`_ provides descriptions and recommendations for many keywords. | ||
A listing of FITS keywords and their descriptions are provided below. | ||
The `required` column describes whether the keyword is required by SOLARNET. | ||
The `data_type` column provides a description of the expected type of the keyword value. | ||
Note that deprecated keywords (such as DATE-OBS or EXPTIME) are explicitely not included in this list. | ||
|
||
|
||
.. csv-table:: Table 1-1: FITS keywords | ||
:file: ../generated/fits_schema.csv | ||
:widths: 30, 70, 30, 30, 30 | ||
:header-rows: 1 | ||
|
||
|
||
In order to support creating FITS headers with the appropriate keywords, the | ||
`sunpy.io.meta.fits_meta` module provides the `~sunpy.io.meta.fits_meta.SolarnetHeader` class. | ||
It is a subclass of `~astropy.io.fits.Header`. | ||
It provides additional functionality like the ability to validate against the solarnet schema as well as support an additional custom schema. | ||
|
||
To create a blank header with only the required keywords | ||
|
||
.. code-block:: python | ||
|
||
from sunpy.io.meta import fits_meta | ||
header = fits_meta.SolarnetHeader() | ||
header['OBSRVTRY'] = 'myawesomemission' | ||
|
||
You can then inspect the keywords and fill in the values as needed. | ||
After you've filled all of your values, you can validate the header with | ||
|
||
.. code-block:: python | ||
|
||
header.validate() | ||
|
||
This will provide warnings for each issue that it finds. | ||
It checks for a number of potential issues such as whether the required keywords | ||
have non-blank values, that deprecrated keywords are not used, and that the values | ||
can be interpreted as the correct types (e.g. dates, quantities, int, floats). | ||
For a complete listing of the issues checked see `~sunpy.io.meta.fits_meta.SolarnetHeader.validate()`. | ||
|
||
You can define your own schema by creating a yaml file with the following structure for each keywords. | ||
|
||
.. code-block:: yaml | ||
|
||
SOLARNET: | ||
description: Fully SOLARNET-compliant=1.0, partially=0.5 | ||
human_readable: Solarnet compatibility | ||
required: true | ||
data_type: float | ||
|
||
You can add an additional optional field `allowed_values: [1.0, 0.5, 0]` if you want to limit the possible options. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,307 @@ | ||
# the following is based on SOLARNET Metadata Recommendations for Solar Observations | ||
# Version 2.0 – 14. August 2023 | ||
# Stein Vidar Hagfors Haugan and Terje Fredvik | ||
# https://arxiv.org/pdf/2011.12139.pdf | ||
AUTHOR: | ||
description: Who designed the observation | ||
human_readable: Author | ||
required: true | ||
data_type: str | ||
BLANK: | ||
description: Value marking undefined pixels before the application of BSCALE, BZERO | ||
human_readable: Missing data indicator | ||
required: true | ||
data_type: str | ||
BTYPE: | ||
description: Description of what the data array represents | ||
human_readable: Data label | ||
required: true | ||
data_type: str | ||
BUNIT: | ||
description: Units of data array | ||
human_readable: Units | ||
required: true | ||
data_type: str | ||
CADENCE: | ||
description: "[s] Planned/commanded cadence (frame to frame spacing)" | ||
human_readable: Planned measurement cadence | ||
required: true | ||
data_type: quantity | ||
CADAVG: | ||
description: "[s] Average (actual) measurement cadence (frame to frame spacing)" | ||
human_readable: Average actual measurement cadence | ||
required: true | ||
data_type: quantity | ||
CADMAX: | ||
description: "[s] Maximum frame-to-frame spacing" | ||
human_readable: Maximum measurement cadence | ||
required: true | ||
data_type: quantity | ||
CADMIN: | ||
description: "[s] Minimum frame-to-frame spacing" | ||
human_readable: Minimum measurement cadence | ||
required: true | ||
data_type: quantity | ||
CAMPAIGN: | ||
description: Coordinated campaign name(s) | ||
human_readable: Observation campaign | ||
required: false | ||
data_type: str | ||
CREATOR: | ||
description: Name of software pipeline that produced the FITS file | ||
human_readable: File Creator | ||
required: true | ||
data_type: str | ||
DATATAGS: | ||
description: Additional information | ||
human_readable: Data Tags | ||
required: false | ||
data_type: str | ||
DATE: | ||
description: FITS file creation date in UTC | ||
human_readable: File Creation Date | ||
required: true | ||
data_type: date | ||
DATE-BEG: | ||
description: Start time of the data aquisition | ||
human_readable: Aquisition start time | ||
required: true | ||
data_type: date | ||
DATE-END: | ||
description: End time of the data aquisition | ||
human_readable: Aquisition end time | ||
required: false | ||
data_type: date | ||
DATE-AVG: | ||
description: Average time of the data aquisition | ||
human_readable: Aquisition average time | ||
required: false | ||
data_type: date | ||
DETECTOR: | ||
description: Name of detector | ||
human_readable: detector | ||
required: true | ||
data_type: str | ||
DSUN_OBS: | ||
description: Distance to Sun | ||
human_readable: Distance to Sun | ||
required: true | ||
data_type: quantity | ||
EXTNAME: | ||
description: Extension name | ||
human_readable: Extension name | ||
required: true | ||
data_type: str | ||
FILENAME: | ||
description: FITS filename | ||
human_readable: Filename | ||
required: true | ||
data_type: str | ||
GEOX_OBS: | ||
description: "[m] Observer's non-fixed geographic X coordinate" | ||
human_readable: Observer X Position | ||
required: false | ||
data_type: quantity | ||
GEOY_OBS: | ||
description: "[m] Observer's non-fixed geographic Y coordinate" | ||
human_readable: Observer Y Position | ||
required: false | ||
data_type: quantity | ||
GEOZ_OBS: | ||
description: "[m] Observer's non-fixed geographic Z coordinate" | ||
human_readable: Observer Z Position | ||
required: false | ||
data_type: quantity | ||
HASH_SW: | ||
description: Commit hash of software applied | ||
human_readable: Software Hash | ||
required: true | ||
data_type: str | ||
INFO_URL: | ||
description: Human-readable web page describing the data set | ||
human_readable: Info url | ||
required: true | ||
data_type: url | ||
INSTRUME: | ||
description: Instrument name | ||
human_readable: Instrument | ||
required: true | ||
data_type: str | ||
LEVEL: | ||
description: Data level of fits file | ||
human_readable: Data level | ||
required: true | ||
data_type: float | ||
MISSION: | ||
description: Mission name | ||
human_readable: Mission | ||
required: true | ||
data_type: str | ||
NSUMEXP: | ||
description: The total number of exposures | ||
human_readable: Number of exposures | ||
required: false | ||
data_type: int | ||
OBS_DESC: | ||
description: Description of observation | ||
human_readable: Observation description | ||
required: false | ||
data_type: str | ||
OBS_HDU: | ||
description: Description of observation | ||
human_readable: Observation description | ||
required: true | ||
data_type: str | ||
OBS_LOG: | ||
description: URL of observation | ||
human_readable: Observation description | ||
required: false | ||
data_type: url | ||
OBS_MODE: | ||
description: Name of predefined settings used during observation | ||
human_readable: Observation mode | ||
required: false | ||
data_type: str | ||
OBSERVER: | ||
description: Who acquired the data | ||
human_readable: Observer | ||
required: false | ||
data_type: str | ||
OBSRVTRY: | ||
description: Satellite name | ||
human_readable: Observatory | ||
required: true | ||
data_type: str | ||
ORIGIN: | ||
description: Location where FITS file has been created | ||
human_readable: File originator | ||
required: true | ||
data_type: str | ||
PLANNER: | ||
description: Observation planner | ||
human_readable: Planner | ||
required: false | ||
data_type: str | ||
PROJECT: | ||
description: Project name | ||
human_readable: Project | ||
required: true | ||
data_type: str | ||
PRSTEP1: | ||
description: First processing step | ||
human_readable: Processing step | ||
required: true | ||
data_type: str | ||
RELEASE: | ||
description: Public release date of data | ||
human_readable: Release date | ||
required: true | ||
data_type: date | ||
RELEASEC: | ||
description: Email address of data release administrator | ||
human_readable: Release administrator | ||
required: true | ||
data_type: email | ||
RESPAPPL: | ||
description: Response function applied | ||
human_readable: Applid response function | ||
required: false | ||
data_type: str | ||
RESOLVPW: | ||
description: Resolving power for spectrometric data | ||
human_readable: Resolving power | ||
required: false | ||
data_type: float | ||
SETTINGS: | ||
description: Additional instrument/acquisition settings | ||
human_readable: Settings | ||
required: false | ||
data_type: str | ||
SLIT_WID: | ||
description: "[arcsec] Slit width" | ||
human_readable: Slit width | ||
required: false | ||
data_type: quantity | ||
SOLARNET: | ||
description: Fully SOLARNET-compliant=1.0, partially=0.5 | ||
human_readable: Solarnet compatibility | ||
required: true | ||
data_type: float | ||
allowed_values: [1.0, 0.5, 0] | ||
TELCONFG: | ||
description: Telescope configuration | ||
human_readable: Telescope configuration | ||
required: false | ||
data_type: str | ||
TELESCOP: | ||
description: Telescope/Sensor name | ||
human_readable: Telescope | ||
required: true | ||
data_type: str | ||
TEXPOSURE: | ||
description: The integration time for a single exposure | ||
human_readable: Single exposure time | ||
required: false | ||
data_type: float | ||
TIMESYS: | ||
description: Time scale of the time-related keywords. | ||
human_readable: Time system | ||
required: true | ||
data_type: str | ||
allowed_values: ["UTC"] | ||
VERS_CAL: | ||
description: Version of calibration pack applied | ||
human_readable: Calibration version | ||
required: true | ||
data_type: str | ||
VERS_SW: | ||
description: Version of software applied | ||
human_readable: Software version | ||
required: true | ||
data_type: str | ||
VERSION: | ||
description: FITS file processing generation/versio | ||
human_readable: Processor version | ||
required: true | ||
data_type: str | ||
WAVEBAND: | ||
description: Human-readable description of the waveband | ||
human_readable: Waveband description | ||
required: false | ||
data_type: str | ||
WAVECOV: | ||
description: The total wavelength coverage if multiple filters (<WAVEMIN1>-<WAVEMAX1>, etc.) | ||
human_readable: Wavelength coverage | ||
required: false | ||
data_type: str | ||
WAVELTH: | ||
description: The characteristic wavelength of the observation | ||
human_readable: Characteristic wavelength | ||
required: false | ||
data_type: float | ||
WAVEMAX: | ||
description: "[Angstrom] Maximum wavelength covered by filter" | ||
human_readable: Maximum wavelength | ||
required: true | ||
data_type: quantity | ||
WAVEMIN: | ||
description: "[Angstrom] Minimum wavelength covered by filter" | ||
human_readable: Minimum wavelength | ||
required: true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems odd to me that this is required. This is a less-well defined quantity for some types of data, e.g. imaging instruments which have a bandpass or a magnetograph. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The recommendations are specific to the kinds of observatories so you are right that this is technically only required for "Spectrographs and filter instruments |
||
data_type: quantity | ||
WAVEREF: | ||
description: Wavelength related kwds in vacuum | ||
human_readable: Wavelength reference | ||
required: true | ||
data_type: str | ||
allowed_values: ["air", "vacuum"] | ||
WAVEUNIT: | ||
description: "Wavelength related kwds have unit: 10^(WAVEUNIT) m" | ||
human_readable: Wavelength unit | ||
required: true | ||
data_type: str | ||
XPOSURE: | ||
description: "[s] Total effective exposure time" | ||
human_readable: Exposure time | ||
required: true | ||
data_type: quantity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made this comment in the meeting discussion today, but I wonder whether we want to store this schema in
sunpy
itself. As this convention was developed elsewhere, I don't think we want to be the ones that own the spec/become de facto in charge of maintaining/updating the spec. My suggestion would be to either pull this schema from its official source or if that doesn't exist in a convenient format, then to put this in a separate, versioned repository that we can pull from such that the schema is maintained separately fromsunpy
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the right approach. Maybe @wafels could host an "official" solarnet repository given that their funding has ended? I'd like the same to be case for the CDF ISTP schema as well to be hosted by the SPDF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do this, although at the moment SDAC does not require compliance with the SOLARNET metadata standard. The heliophysics data policy does ask for FITS files for solar data, and the HEASARC hosts FITS verification tools. At the moment, testing against the schema would be purely optional for an instrument team.