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

57 statements  

« prev     ^ index     » next       coverage.py v7.1.0, created at 2023-02-05 18:55 -0800

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 

27 

28from lsst.afw.image import TransmissionCurve 

29from lsst.utils import getPackageDir 

30from . import hscFilters 

31 

32__all__ = ("getOpticsTransmission", "getSensorTransmission", "getAtmosphereTransmission", 

33 "getFilterTransmission",) 

34 

35DATA_DIR = os.path.join(getPackageDir("obs_subaru"), "hsc", "transmission") 

36 

37HSC_BEGIN = "2012-12-18" # initial date for curves valid for entire lifetime of HSC 

38 

39 

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 

53 

54 

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. 

58 

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) 

86 

87 

88def getOpticsTransmission(): 

89 """Return a dictionary of TransmissionCurves describing the combined 

90 throughput of HSC and the Subaru primary mirror. 

91 

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. 

96 

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 } 

107 

108 

109def getSensorTransmission(): 

110 """Return a nested dictionary of TransmissionCurves describing the 

111 throughput of each sensor. 

112 

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. 

116 

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)}} 

122 

123 

124def getAtmosphereTransmission(): 

125 """Return a dictionary of TransmissionCurves describing the atmospheric 

126 throughput at Mauna Kea. 

127 

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. 

131 

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} 

137 

138 

139def getFilterTransmission(): 

140 """Return a nested dictionary of TransmissionCurves describing the 

141 throughput of each HSC filter. 

142 

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. 

146 

147 Filter curve names are in the long form used as data ID values (e.g. 

148 'HSC-I'). 

149 

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}