Coverage for python/lsst/obs/hsc/makeTransmissionCurves.py : 18%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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, Filter
29from lsst.utils import getPackageDir
30from .hscMapper import HscMapper
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 HscMapper.addFilters()
45 if short.startswith("HSC"):
46 return short
47 if short.startswith("NB") or short.startswith("IB"):
48 num = int(short[2:].lstrip("0"))
49 return "%s%04d" % (short[:2], num)
50 f = Filter(short)
51 for a in f.getAliases():
52 if a.startswith("HSC") or a.startswith("NB") or a.startswith("IB"):
53 return a
54 return short
57def readTransmissionCurveFromFile(filename, unit="angstrom", atMin=None, atMax=None):
58 """Load a spatial TransmissionCurve from a text file with wavelengths and
59 throughputs in columns.
61 Parameters
62 ----------
63 filename : `str`
64 Name of the file to read.
65 unit : `str`
66 Wavelength unit; one of "nm" or "angstrom".
67 atMin : `float`
68 Throughput to use at wavelengths below the tabulated minimum. If
69 ``None``, the tabulated throughput at the mininum will be used.
70 atMax : `float`
71 Throughput to use at wavelengths above the tabulated maximum. If
72 ``None``, the tabulated throughput at the maximum will be used.
73 """
74 wavelengths, throughput = np.loadtxt(os.path.join(DATA_DIR, filename), usecols=[0, 1], unpack=True)
75 i = np.argsort(wavelengths)
76 wavelengths = wavelengths[i]
77 throughput = throughput[i]
78 if unit == "nm":
79 wavelengths *= 10
80 elif unit != "angstrom":
81 raise ValueError("Invalid wavelength unit")
82 if atMin is None:
83 atMin = throughput[0]
84 if atMax is None:
85 atMax = throughput[-1]
86 return TransmissionCurve.makeSpatiallyConstant(throughput=throughput, wavelengths=wavelengths,
87 throughputAtMin=atMin, throughputAtMax=atMax)
90def getOpticsTransmission():
91 """Return a dictionary of TransmissionCurves describing the combined
92 throughput of HSC and the Subaru primary mirror.
94 Dictionary keys are string dates (YYYY-MM-DD) indicating the beginning of
95 the validity period for the curve stored as the associated dictionary
96 value. If the curve is spatially varying, it will be defined in focal
97 plane coordinates.
99 Dictionary values may be None to indicate that no TransmissionCurve is
100 valid after the date provided in the key.
101 """
102 mirror2010 = readTransmissionCurveFromFile("M1-2010s.txt", unit="nm")
103 camera = readTransmissionCurveFromFile("throughput_popt2.txt")
104 camera *= readTransmissionCurveFromFile("throughput_win.txt")
105 return {
106 HSC_BEGIN: mirror2010*camera,
107 "2017-10-01": None # mirror recoating begins, approximately
108 }
111def getSensorTransmission():
112 """Return a nested dictionary of TransmissionCurves describing the
113 throughput of each sensor.
115 Outer directionary keys are string dates (YYYY-MM-DD), with values
116 a dictionary mapping CCD ID to TransmissionCurve. If the curve
117 is spatially varying, it will be defined in pixel coordinates.
119 Outer dictionary values may be None to indicate that no TransmissionCurve
120 is valid after the date provided in the key.
121 """
122 qe = readTransmissionCurveFromFile("qe_ccd_HSC.txt", atMin=0.0, atMax=0.0)
123 return {HSC_BEGIN: {n: qe for n in range(112)}}
126def getAtmosphereTransmission():
127 """Return a dictionary of TransmissionCurves describing the atmospheric
128 throughput at Mauna Kea.
130 Dictionary keys are string dates (YYYY-MM-DD) indicating the beginning of
131 the validity period for the curve stored as the associated dictionary
132 value. The curve is guaranteed not to be spatially-varying.
134 Dictionary values may be None to indicate that no TransmissionCurve is
135 valid after the date provided in the key.
136 """
137 average = readTransmissionCurveFromFile("modtran_maunakea_am12_pwv15_binned10ang.dat")
138 return {HSC_BEGIN: average}
141def getFilterTransmission():
142 """Return a nested dictionary of TransmissionCurves describing the
143 throughput of each HSC filter.
145 Outer directionary keys are string dates (YYYY-MM-DD), with values
146 a dictionary mapping filter name to TransmissionCurve. If the curve
147 is spatially varying, it will be defined in pixel coordinates.
149 Filter curve names are in the long form used as data ID values (e.g.
150 'HSC-I').
152 Outer dictionary values may be None to indicate that no TransmissionCurve
153 is valid after the date provided in the key.
154 """
155 module = {}
156 filename = os.path.join(DATA_DIR, "filterTraces.py")
157 with open(filename) as file:
158 exec(compile(file.read(), filename, mode='exec'), module)
159 result = {}
160 for band, data in module["FILTER_DATA"].items():
161 result[getLongFilterName(band)] = TransmissionCurve.makeRadial(
162 throughput=data["T"], wavelengths=data["lam"]*10,
163 radii=data['radius']/module["PIXEL_SIZE"],
164 throughputAtMin=0.0, throughputAtMax=0.0
165 )
166 for filename in glob.glob(os.path.join(DATA_DIR, "wHSC-*.txt")):
167 band = getLongFilterName(os.path.split(filename)[1][len("wHSC-"): -len(".txt")])
168 if band not in result:
169 result[band] = readTransmissionCurveFromFile(filename, atMin=0.0, atMax=0.0)
170 return {HSC_BEGIN: result}