Coverage for python / lsst / analysis / tools / math.py: 24%

94 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-15 00:23 +0000

1# This file is part of analysis_tools. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22__all__ = ( 

23 "cos", 

24 "divide", 

25 "isPercent", 

26 "fluxToMag", 

27 "nanMax", 

28 "nanMean", 

29 "nanMin", 

30 "nanMedian", 

31 "nanSigmaMad", 

32 "nanStd", 

33 "power", 

34 "sigmaMad", 

35 "sin", 

36 "sqrt", 

37) 

38 

39import warnings 

40from typing import cast 

41 

42import astropy.units as u 

43import numpy as np 

44import scipy.stats as sps 

45 

46from .interfaces import Scalar, Vector 

47from .warning_control import ( 

48 filterwarnings_action, 

49 numpy_all_nan, 

50 numpy_all_nan_slice, 

51 numpy_divide_zero_divide, 

52 numpy_divide_zero_log, 

53 numpy_divide_zero_log10, 

54 numpy_dof_zero, 

55 numpy_invalid_value_cos, 

56 numpy_invalid_value_divide, 

57 numpy_invalid_value_log, 

58 numpy_invalid_value_log10, 

59 numpy_invalid_value_power, 

60 numpy_invalid_value_scalar_divide, 

61 numpy_invalid_value_sin, 

62 numpy_invalid_value_sqrt, 

63 numpy_invalid_value_subtract, 

64 numpy_mean_empty, 

65) 

66 

67 

68def cos(values: Scalar | Vector) -> Scalar | Vector: 

69 """Return the sqrt of values.""" 

70 with warnings.catch_warnings(): 

71 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_cos) 

72 result = np.cos(values) 

73 return result 

74 

75 

76def divide(dividend: Scalar | Vector, divisor: Scalar | Vector) -> Scalar | Vector: 

77 """Return dividend/divisor.""" 

78 with warnings.catch_warnings(): 

79 warnings.filterwarnings(filterwarnings_action, numpy_divide_zero_divide) 

80 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_divide) 

81 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_scalar_divide) 

82 result = dividend / divisor 

83 return result 

84 

85 

86def fluxToMag( 

87 flux: Scalar | Vector, 

88 flux_unit: u.Unit | str = u.nJy, 

89 return_millimags: bool = False, 

90) -> Scalar | Vector: 

91 """Convert fluxes to magnitudes. 

92 

93 Parameters 

94 ---------- 

95 flux 

96 The flux(es) to convert. 

97 flux_unit 

98 The flux unit, as an object or string. Default astropy.units.nJy. 

99 return_millimags 

100 Whether to return millimags instead of mags. 

101 

102 Returns 

103 ------- 

104 mags 

105 The magnitude(s) converted from the flux(es). 

106 """ 

107 if not isinstance(flux_unit, u.Unit): 

108 flux_unit = u.Unit(flux_unit) 

109 with warnings.catch_warnings(): 

110 warnings.filterwarnings(filterwarnings_action, numpy_divide_zero_log10) 

111 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_log10) 

112 mag = (np.asarray(flux) * flux_unit).to(u.ABmag).value # type: ignore 

113 if return_millimags: 

114 mag *= 1000 

115 return mag 

116 

117 

118def isPercent(value: Scalar) -> bool: 

119 """Return true if the value is between 0-100""" 

120 result = 0.0 <= value <= 100.0 

121 return result 

122 

123 

124def log(values: Scalar | Vector) -> Scalar | Vector: 

125 """Return the natural logarithm of values.""" 

126 with warnings.catch_warnings(): 

127 warnings.filterwarnings(filterwarnings_action, numpy_divide_zero_log) 

128 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_log) 

129 result = np.log(values) 

130 return result 

131 

132 

133def log10(values: Scalar | Vector) -> Scalar | Vector: 

134 """Return the natural logarithm of values.""" 

135 with warnings.catch_warnings(): 

136 warnings.filterwarnings(filterwarnings_action, numpy_divide_zero_log10) 

137 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_log10) 

138 result = np.log10(values) 

139 return result 

140 

141 

142def nanSigmaMad(vector: Vector) -> Scalar: 

143 """Return the sigma_MAD of a vector.""" 

144 with warnings.catch_warnings(): 

145 # This is needed to catch inf median in sigma_mad 

146 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_subtract) 

147 result = sps.median_abs_deviation(np.asarray(vector), axis=None, scale="normal", nan_policy="omit") 

148 return cast(Scalar, result) 

149 

150 

151def nanMax(vector: Vector) -> Scalar: 

152 """Return the max of a vector.""" 

153 with warnings.catch_warnings(): 

154 warnings.filterwarnings(filterwarnings_action, numpy_all_nan) 

155 result = float(np.nanmax(np.asarray(vector))) 

156 return cast(Scalar, result) 

157 

158 

159def nanMean(vector: Vector) -> Scalar: 

160 """Return the mean of a vector.""" 

161 with warnings.catch_warnings(): 

162 warnings.filterwarnings(filterwarnings_action, numpy_all_nan_slice) 

163 warnings.filterwarnings(filterwarnings_action, numpy_mean_empty) 

164 result = float(np.nanmean(np.asarray(vector))) 

165 return cast(Scalar, result) 

166 

167 

168def nanMedian(vector: Vector) -> Scalar: 

169 """Return the median of a vector.""" 

170 with warnings.catch_warnings(): 

171 warnings.filterwarnings(filterwarnings_action, numpy_all_nan_slice) 

172 warnings.filterwarnings(filterwarnings_action, numpy_mean_empty) 

173 result = float(np.nanmedian(np.asarray(vector))) 

174 return cast(Scalar, result) 

175 

176 

177def nanMin(vector: Vector) -> Scalar: 

178 """Return the max of a vector.""" 

179 with warnings.catch_warnings(): 

180 warnings.filterwarnings(filterwarnings_action, numpy_all_nan) 

181 result = float(np.nanmin(np.asarray(vector))) 

182 return cast(Scalar, result) 

183 

184 

185def nanStd(vector: Vector) -> Scalar: 

186 with warnings.catch_warnings(): 

187 warnings.filterwarnings(filterwarnings_action, numpy_dof_zero) 

188 result = float(np.nanstd(np.asarray(vector))) 

189 return cast(Scalar, result) 

190 

191 

192def power(values: Scalar | Vector, power: float) -> Scalar | Vector: 

193 """Return the sqrt of values.""" 

194 with warnings.catch_warnings(): 

195 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_power) 

196 result = np.power(values, power) 

197 return result 

198 

199 

200def sigmaMad(vector: Vector) -> Scalar: 

201 return cast(Scalar, sps.median_abs_deviation(np.asarray(vector), scale="normal", nan_policy="propagate")) 

202 

203 

204def sin(values: Scalar | Vector) -> Scalar | Vector: 

205 """Return the sin of values.""" 

206 with warnings.catch_warnings(): 

207 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_sin) 

208 result = np.sin(values) 

209 return result 

210 

211 

212def sqrt(values: Scalar | Vector) -> Scalar | Vector: 

213 """Return the sqrt of values.""" 

214 with warnings.catch_warnings(): 

215 warnings.filterwarnings(filterwarnings_action, numpy_invalid_value_sqrt) 

216 result = np.sqrt(values) 

217 return result