Coverage for python/lsst/obs/hsc/makeTransmissionCurves.py: 19%
57 statements
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-12 03:48 -0700
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-12 03:48 -0700
1#!/usr/bin/env python
2#
3# LSST Data Management System
4#
5# Copyright 2018 AURA/LSST.
6#
7# This product includes software developed by the
8# LSST Project (http://www.lsst.org/).
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the LSST License Statement and
21# the GNU General Public License along with this program. If not,
22# see <https://www.lsstcorp.org/LegalNotices/>.
23#
24import os
25import glob
26import numpy as np
28from lsst.afw.image import TransmissionCurve
29from lsst.utils import getPackageDir
30from . import hscFilters
32__all__ = ("getOpticsTransmission", "getSensorTransmission", "getAtmosphereTransmission",
33 "getFilterTransmission",)
35DATA_DIR = os.path.join(getPackageDir("obs_subaru"), "hsc", "transmission")
37HSC_BEGIN = "2012-12-18" # initial date for curves valid for entire lifetime of HSC
40def getLongFilterName(short):
41 """Return a long HSC filter name (e.g. 'HSC-R') that's usable as a data ID
42 value from the short one (e.g. 'r') declared canonical in afw.image.Filter.
43 """
44 if short.startswith("HSC"):
45 return short
46 if short.startswith("NB") or short.startswith("IB"):
47 num = int(short[2:].lstrip("0"))
48 return "%s%04d" % (short[:2], num)
49 for filter in hscFilters.HSC_FILTER_DEFINITIONS:
50 if short == filter.afw_name or short == filter.band:
51 return filter.physical_filter
52 return short
55def readTransmissionCurveFromFile(filename, unit="angstrom", atMin=None, atMax=None):
56 """Load a spatial TransmissionCurve from a text file with wavelengths and
57 throughputs in columns.
59 Parameters
60 ----------
61 filename : `str`
62 Name of the file to read.
63 unit : `str`
64 Wavelength unit; one of "nm" or "angstrom".
65 atMin : `float`
66 Throughput to use at wavelengths below the tabulated minimum. If
67 ``None``, the tabulated throughput at the mininum will be used.
68 atMax : `float`
69 Throughput to use at wavelengths above the tabulated maximum. If
70 ``None``, the tabulated throughput at the maximum will be used.
71 """
72 wavelengths, throughput = np.loadtxt(os.path.join(DATA_DIR, filename), usecols=[0, 1], unpack=True)
73 i = np.argsort(wavelengths)
74 wavelengths = wavelengths[i]
75 throughput = throughput[i]
76 if unit == "nm":
77 wavelengths *= 10
78 elif unit != "angstrom":
79 raise ValueError("Invalid wavelength unit")
80 if atMin is None:
81 atMin = throughput[0]
82 if atMax is None:
83 atMax = throughput[-1]
84 return TransmissionCurve.makeSpatiallyConstant(throughput=throughput, wavelengths=wavelengths,
85 throughputAtMin=atMin, throughputAtMax=atMax)
88def getOpticsTransmission():
89 """Return a dictionary of TransmissionCurves describing the combined
90 throughput of HSC and the Subaru primary mirror.
92 Dictionary keys are string dates (YYYY-MM-DD) indicating the beginning of
93 the validity period for the curve stored as the associated dictionary
94 value. If the curve is spatially varying, it will be defined in focal
95 plane coordinates.
97 Dictionary values may be None to indicate that no TransmissionCurve is
98 valid after the date provided in the key.
99 """
100 mirror2010 = readTransmissionCurveFromFile("M1-2010s.txt", unit="nm")
101 camera = readTransmissionCurveFromFile("throughput_popt2.txt")
102 camera *= readTransmissionCurveFromFile("throughput_win.txt")
103 return {
104 HSC_BEGIN: mirror2010*camera,
105 "2017-10-01": None # mirror recoating begins, approximately
106 }
109def getSensorTransmission():
110 """Return a nested dictionary of TransmissionCurves describing the
111 throughput of each sensor.
113 Outer directionary keys are string dates (YYYY-MM-DD), with values
114 a dictionary mapping CCD ID to TransmissionCurve. If the curve
115 is spatially varying, it will be defined in pixel coordinates.
117 Outer dictionary values may be None to indicate that no TransmissionCurve
118 is valid after the date provided in the key.
119 """
120 qe = readTransmissionCurveFromFile("qe_ccd_HSC.txt", atMin=0.0, atMax=0.0)
121 return {HSC_BEGIN: {n: qe for n in range(112)}}
124def getAtmosphereTransmission():
125 """Return a dictionary of TransmissionCurves describing the atmospheric
126 throughput at Mauna Kea.
128 Dictionary keys are string dates (YYYY-MM-DD) indicating the beginning of
129 the validity period for the curve stored as the associated dictionary
130 value. The curve is guaranteed not to be spatially-varying.
132 Dictionary values may be None to indicate that no TransmissionCurve is
133 valid after the date provided in the key.
134 """
135 average = readTransmissionCurveFromFile("modtran_maunakea_am12_pwv15_binned10ang.dat")
136 return {HSC_BEGIN: average}
139def getFilterTransmission():
140 """Return a nested dictionary of TransmissionCurves describing the
141 throughput of each HSC filter.
143 Outer directionary keys are string dates (YYYY-MM-DD), with values
144 a dictionary mapping filter name to TransmissionCurve. If the curve
145 is spatially varying, it will be defined in pixel coordinates.
147 Filter curve names are in the long form used as data ID values (e.g.
148 'HSC-I').
150 Outer dictionary values may be None to indicate that no TransmissionCurve
151 is valid after the date provided in the key.
152 """
153 module = {}
154 filename = os.path.join(DATA_DIR, "filterTraces.py")
155 with open(filename) as file:
156 exec(compile(file.read(), filename, mode='exec'), module)
157 result = {}
158 for band, data in module["FILTER_DATA"].items():
159 result[getLongFilterName(band)] = TransmissionCurve.makeRadial(
160 throughput=data["T"], wavelengths=data["lam"]*10,
161 radii=data['radius']/module["PIXEL_SIZE"],
162 throughputAtMin=0.0, throughputAtMax=0.0
163 )
164 for filename in glob.glob(os.path.join(DATA_DIR, "wHSC-*.txt")):
165 band = getLongFilterName(os.path.split(filename)[1][len("wHSC-"): -len(".txt")])
166 if band not in result:
167 result[band] = readTransmissionCurveFromFile(filename, atMin=0.0, atMax=0.0)
168 return {HSC_BEGIN: result}