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

DM-40740: Create an obs_package to handle the fiber spectrographs #1

Merged
merged 42 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3c8ad40
Python code for the package, transferred from lsst-dm.
aferte Jan 18, 2024
3b4a2ae
Add policy, transferred from lsst-dm.
aferte Jan 18, 2024
fd56cc4
Update eups packages list.
aferte Jan 18, 2024
3c5637a
Remove deprecated flag.
aferte Jan 23, 2024
78f5e7d
Harmonize names.
aferte Jan 23, 2024
f34a6c9
Update init.
aferte Jan 23, 2024
7d98960
Add instrument test from lsst dm.
aferte Jan 23, 2024
06acd12
Harmonize naming.
aferte Jan 23, 2024
d320618
Add butler plugin.
aferte Jan 23, 2024
6441a4f
Update name in doc.
aferte Jan 23, 2024
c8ce2b7
Add tests and update default setup.
aferte Jan 23, 2024
97f125e
Add isr pipeline.
aferte Jan 23, 2024
229442a
Readme, setup and linting.
aferte Jan 23, 2024
9ce6b42
Change detector name.
aferte Jan 29, 2024
8b21fde
Update default band name.
aferte Jan 31, 2024
a71b9ca
Update method type in spectrum.
aferte Jan 31, 2024
00b1681
Update setup requirements.
aferte Jan 31, 2024
24106db
Formatter with consistent methods.
aferte Feb 1, 2024
924193a
Change from fitsio to astropy.
aferte Feb 1, 2024
275fc7c
Add extension to raw formatter.
aferte Feb 1, 2024
ac6aa91
Add serial number.
aferte Feb 1, 2024
9d4a7f1
Update to translator.
aferte Feb 2, 2024
6b3ab9c
Simplify header udpate.
aferte Feb 2, 2024
a58c5fc
Remove physical filter in instrument definition.
aferte Feb 2, 2024
e9a0e6e
Update seq num and exposure id.
aferte Feb 2, 2024
6eeb8b5
Change test data.
aferte Feb 2, 2024
7995fda
Add class documentation.
aferte Feb 3, 2024
425f43b
Remove translator methods to parent class methods instead.
aferte Feb 3, 2024
abd1cdf
Update doc.
aferte Feb 3, 2024
c5cce55
Add purpose.
aferte Feb 6, 2024
0ff0dd4
Remove data manager class from spectrum and add detector to FiberSpec…
aferte Feb 9, 2024
4245831
Add data manager.
aferte Feb 9, 2024
39c280e
Use observation info.
aferte Feb 9, 2024
7848cd4
Add new lines.
aferte Feb 22, 2024
c2ba25b
Replace instance attribute to metadata.
aferte Feb 22, 2024
740e31d
Changed attribute to temporary variable.
aferte Feb 22, 2024
0dbe239
Add doc strings.
aferte Feb 22, 2024
de5467a
Add raise when format v changes value.
aferte Feb 22, 2024
6a73187
Small update.
aferte Feb 22, 2024
9a9a293
Write and read mask and variance plane and change check on formatv.
aferte Feb 27, 2024
8fb4874
Update translator.
aferte Feb 27, 2024
c255fbc
Correct attribute in returm.
aferte Feb 29, 2024
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
23 changes: 6 additions & 17 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
name: lint

on:
- push
- pull_request
push:
branches:
- main
pull_request:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.7

- name: Install
run: pip install -r <(curl https://raw.githubusercontent.com/lsst/linting/main/requirements.txt)

- name: Run linter
run: flake8
call-workflow:
uses: lsst/rubin_workflows/.github/workflows/lint.yaml@main
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.sconsign.dblite
config.log
.sconf_temp
.scons*
*.o
*.os
*.so
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# obs_fiberspectrograph

``obs_fiberspectrograph`` is a package in the `LSST Science Pipelines <https://pipelines.lsst.io>`_.

Package to ingest fiber spectrograph data.
7 changes: 0 additions & 7 deletions README.rst

This file was deleted.

24 changes: 24 additions & 0 deletions pipelines/fiberspectrograph/ISR.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
description: ISR for Rubin fiber spectrographs
instrument: lsst.obs.fiberspectrograph.FiberSpectrograph

tasks:
isr:
class: lsst.obs.fiberspectrograph.isrTask.IsrTask
config:
doBias: false
doCrosstalk: false
doVariance: false
doLinearize: false
doDefect: false
doDark: false
doFlat: false
doFringe: false
doAssembleCcd: false
doNanMasking: false
doSaturation: true
doWidenSaturationTrails: false
doCameraSpecificMasking: false
doSetBadRegions: false
doInterpolate: false
doMeasureBackground: false
doStandardStatistics: false
84 changes: 84 additions & 0 deletions policy/fiberSpectrograph.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# This file is part of obs_fiberspectrograph.
#
# Developed for the LSST Data Management System.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program. If not,
# see <http://www.lsstcorp.org/LegalNotices/>.
#
#

name : "FiberSpec"
plateScale : 1.0

# Provide transformations *from* the nativeSys *to* the specified system (e.g. FieldAngle)
transforms :
nativeSys : FocalPlane
FieldAngle :
transformType : radial
coeffs : [0.0, 1.0, 0.0] # radial distortion coefficients (c_0 + c_1 r + c_2 r^2 + ...)

#
# A list of detectors in the camera; we only have one
#
CCDs : &CCDs
"ccd0" :
detectorType : 0
aferte marked this conversation as resolved.
Show resolved Hide resolved
id : 0
serial : "1606191U1"
offset : [0, 0]
refpos : [0, 0]
#
# [[x0, y0], [xSize, ySize]]
bbox : &bbox [[ 0, 0], [ 2048, 1]] # total bbox of trimmed detector
pixelSize : [1, 1] # in mm
transformDict : {nativeSys : 'Pixels', transforms : None}
transposeDetector : False
pitch : 0.0 # (degrees)
yaw : 0.0 # rotation in plane of camera (degrees)
roll : 0.0 # (degrees)

amplifiers: # only 1 amplifier
"0":
hdu : 1 # Only one HDU in the file

ixy : [0, 0]
readCorner : LL
flipXY : [False, False]
perAmpData : False # is the amp data split across multiple HDUs/Files?

# [[x0, y0], [xSize, ySize]]
rawBBox : *bbox
rawDataBBox : *bbox
rawSerialPrescanBBox : [[0, 0], [0, 0]] # serial prescan
rawSerialOverscanBBox : [[0, 0], [0, 0]] # serial overscan
rawParallelPrescanBBox : [[0, 0], [0, 0]] # pixels digitised before first parallel
rawParallelOverscanBBox : [[0, 0], [0, 0]] # parallel overscan

saturation : 16383 # saturation level, DN XXX Should this be in electrons?

# Linearity correction is still under discussion, so this is a placeholder.
linearityType : PROPORTIONAL
linearityThreshold : 0
linearityMax : 65535
linearityCoeffs : [0, 65535] # == [linearityThreshold, linearityMax]

gain : 1.00
readNoise : 10
2 changes: 2 additions & 0 deletions python/lsst/obs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
2 changes: 2 additions & 0 deletions python/lsst/obs/fiberspectrograph/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from .version import * # Generated by sconsUtils
from ._instrument import *
from .spectrum import *
78 changes: 78 additions & 0 deletions python/lsst/obs/fiberspectrograph/_instrument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# This file is part of obs_fiberspectrograph
#
# Developed for the LSST Data Management System.
# This product includes software developed by the LSST Project
# (http://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

__all__ = ("FiberSpectrograph", )

import os.path

import lsst.obs.base.yamlCamera as yamlCamera
from lsst.utils import getPackageDir
from lsst.obs.base import VisitSystem
from lsst.obs.lsst import LsstCam
from .filters import FIBER_SPECTROGRAPH_FILTER_DEFINITIONS
from .translator import FiberSpectrographTranslator

PACKAGE_DIR = getPackageDir("obs_fiberspectrograph")


class FiberSpectrograph(LsstCam):
"""Gen3 instrument for the Rubin fiber spectrographs

Parameters
----------
camera : `lsst.cameraGeom.Camera`
Camera object from which to extract detector information.
filters : `list` of `FilterDefinition`
An ordered list of filters to define the set of PhysicalFilters
associated with this instrument in the registry.
"""
filterDefinitions = FIBER_SPECTROGRAPH_FILTER_DEFINITIONS
instrument = "FiberSpec"
policyName = "fiberSpectrograph"
translatorClass = FiberSpectrographTranslator
visitSystem = VisitSystem.BY_SEQ_START_END
raw_definition = ("rawSpectrum",
("instrument", "exposure", "detector"),
"FiberSpectrum")

@classmethod
def getCamera(cls):
# Constructing a YAML camera takes a long time but we rely on
# yamlCamera to cache for us.
# N.b. can't inherit as PACKAGE_DIR isn't in the class
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be open to you patching obs_lsst to add a package_dir class property so you could avoid copying this method.

Copy link
Collaborator Author

@aferte aferte Feb 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good - is it ok to push this to a future ticket to keep things simple for now?

cameraYamlFile = os.path.join(PACKAGE_DIR, "policy", f"{cls.policyName}.yaml")
return yamlCamera.makeCamera(cameraYamlFile)

def getRawFormatter(self, dataId):
# Docstring inherited from Instrument.getRawFormatter
# local import to prevent circular dependency
from .rawFormatter import FiberSpectrographRawFormatter
return FiberSpectrographRawFormatter

def extractDetectorRecord(self, camGeomDetector):
"""Create a Gen3 Detector entry dict from a cameraGeom.Detector.
"""
return dict(
instrument=self.getName(),
id=camGeomDetector.getId(),
full_name=camGeomDetector.getName(),
purpose=str(camGeomDetector.getType()).split(".")[-1]
)
aferte marked this conversation as resolved.
Show resolved Hide resolved
129 changes: 129 additions & 0 deletions python/lsst/obs/fiberspectrograph/data_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# This file is part of obs_fiberspectrograph
#
# Developed for the LSST Data Management System.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import astropy.io.fits


class DataManager:
"""A data packager for `Spectrum` objects
that comes from the ts_fiberspectrograph package
"""

wcs_table_name = "WCS-TAB"
"""Name of the table containing the wavelength WCS (EXTNAME)."""
wcs_table_ver = 1
"""WCS table version (EXTVER)."""
wcs_column_name = "wavelength"
"""Name of the table column containing the wavelength information."""

# The version of the FITS file format produced by this class.
FORMAT_VERSION = 1

def __init__(self, spectrum):
self.spectrum = spectrum

def make_hdulist(self):
"""Generate a FITS hdulist built from SpectrographData.
Parameters
----------
spec : `SpectrographData`
The data from which to build the FITS hdulist.
Returns
-------
hdulist : `astropy.io.fits.HDUList`
The FITS hdulist.
"""
hdu1 = self.make_primary_hdu()
hdu2 = self.make_wavelength_hdu()
hdu3, hdu4 = self.make_maskvariance_hdu()
return astropy.io.fits.HDUList([hdu1, hdu2, hdu3, hdu4])

def make_fits_header(self):
"""Return a FITS header built from a Spectrum"""
hdr = astropy.io.fits.Header()

hdr["FORMAT_V"] = self.FORMAT_VERSION
hdr.update(self.spectrum.metadata)

# WCS headers - Use -TAB WCS definition
wcs_cards = [
"WCSAXES = 1 / Number of WCS axes",
"CRPIX1 = 0.0 / Reference pixel on axis 1",
"CRVAL1 = 0.0 / Value at ref. pixel on axis 1",
"CNAME1 = 'Wavelength' / Axis name for labeling purposes",
"CTYPE1 = 'WAVE-TAB' / Wavelength axis by lookup table",
"CDELT1 = 1.0 / Pixel size on axis 1",
f"CUNIT1 = '{self.spectrum.wavelength.unit.name:8s}' / Units for axis 1",
f"PV1_1 = {self.wcs_table_ver:20d} / EXTVER of bintable extension for -TAB arrays",
f"PS1_0 = '{self.wcs_table_name:8s}' / EXTNAME of bintable extension for -TAB arrays",
f"PS1_1 = '{self.wcs_column_name:8s}' / Wavelength coordinate array",
]
for c in wcs_cards:
hdr.append(astropy.io.fits.Card.fromstring(c))

return hdr

def make_primary_hdu(self):
"""Return the primary HDU built from a Spectrum."""

hdu = astropy.io.fits.PrimaryHDU(
data=self.spectrum.flux, header=self.make_fits_header()
)
return hdu

def make_maskvariance_hdu(self):
"""Return the HDU for the mask and variance plane."""
hdr_mask = astropy.io.fits.Header()
hdr_mask["EXTTYPE"] = 'MASK '
hdr_mask["EXTNAME"] = 'MASK '
hdu_mask = astropy.io.fits.ImageHDU(
data=self.spectrum.mask, header=hdr_mask
)

hdr_variance = astropy.io.fits.Header()
hdr_variance["EXTTYPE"] = 'VARIANCE'
hdr_variance["EXTNAME"] = 'VARIANCE'
hdu_variance = astropy.io.fits.ImageHDU(
data=self.spectrum.variance, header=hdr_variance
)
return hdu_mask, hdu_variance

def make_wavelength_hdu(self):
"""Return the wavelength HDU built from a Spectrum."""

# The wavelength array must be 2D (N, 1) in numpy but (1, N) in FITS
wavelength = self.spectrum.wavelength.reshape([self.spectrum.wavelength.size, 1])

# Create a Table. It will be a single element table
table = astropy.table.Table()

# Create the wavelength column
# Create the column explicitly since it is easier to ensure the
# shape this way.
wavecol = astropy.table.Column([wavelength], unit=wavelength.unit.name)

# The column name must match the PS1_1 entry from the primary HDU
table[self.wcs_column_name] = wavecol

# The name MUST match the value of PS1_0 and the version MUST
# match the value of PV1_1
hdu = astropy.io.fits.BinTableHDU(table, name=self.wcs_table_name, ver=1)
return hdu
5 changes: 5 additions & 0 deletions python/lsst/obs/fiberspectrograph/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lsst.obs.base import FilterDefinition, FilterDefinitionCollection

FIBER_SPECTROGRAPH_FILTER_DEFINITIONS = FilterDefinitionCollection(
FilterDefinition(band="white", physical_filter="empty"),
)
Loading
Loading