Coverage for middlelayer / ngect / utils.py: 66.67%

21 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-16 06:04 +0000

1# Copyright 2023 Associated Universities, Inc. 

2# 

3# This file is part of ngVLA Exposure Calculator Tool (ngECT). 

4# 

5# ngECT is free software: you can redistribute it and/or modify 

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

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

8# any later version. 

9# 

10# ngECT is distributed in the hope that it will be useful, 

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

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

13# GNU General Public License for more details. 

14# 

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

16# along with ngECT. If not, see <https://www.gnu.org/licenses/>. 

17 

18import bisect 

19import glob 

20import logging 

21import os 

22import re 

23 

24import numpy as np 

25 

26logger = logging.getLogger(__name__) 

27 

28 

29def get_si_prefix(value: float, select: str = "mu", lztol: int = 0) -> tuple: 

30 """Choose a readable SI prefix for a numeric value. 

31 

32 Determines the prefix that minimizes leading zeros (within a tolerance) 

33 and keeps a small number of digits before the decimal point after 

34 scaling the value. 

35 

36 Parameters 

37 ---------- 

38 value : float 

39 The numeric value to scale. 

40 select : str, optional 

41 String containing the set of candidate SI prefixes to consider. 

42 Must be a subset of ``"yzafpnum kMGTPEZY"`` (a space represents no prefix). 

43 Defaults to ``"mu"`` (micro and none). 

44 lztol : int, optional 

45 Leading-zero tolerance used when selecting the prefix. Higher values 

46 allow more leading zeros before switching to a smaller unit. Default is ``0``. 

47 

48 Returns 

49 ------- 

50 tuple 

51 ``(prefix: str, scale: float)`` where ``prefix`` is the chosen SI 

52 prefix symbol (e.g., ``"m"``, ``"u"``, ``"k"``, or ``""`` for none) 

53 and ``scale`` is the multiplicative factor corresponding to that prefix 

54 (e.g., ``1e-3`` for ``"m"``, ``1e6`` for ``"M"``). 

55 

56 Notes 

57 ----- 

58 The full ordered table of supported prefixes is:: 

59 

60 "yzafpnum kMGTPEZY" 

61 

62 The space character denotes the base unit (no prefix). 

63 

64 Examples 

65 -------- 

66 Frequency value in Hz: 

67 

68 >>> get_si_prefix(10**7, select='kMGT') 

69 ('M', 1000000.0) 

70 

71 Flux value in Jy: 

72 

73 >>> get_si_prefix(1.0, select='um') 

74 ('', 1.0) 

75 >>> get_si_prefix(0.0, select='um') 

76 ('', 1.0) 

77 >>> get_si_prefix(-0.9, select='um') 

78 ('m', 0.001) 

79 >>> get_si_prefix(0.9, select='um', lztol=1) 

80 ('', 1.0) 

81 >>> get_si_prefix(1e-7, select='um') 

82 ('u', 1e-06) 

83 >>> get_si_prefix(1e3, select='um') 

84 ('', 1.0) 

85 """ 

86 if value == 0: 

87 return "", 1.0 

88 else: 

89 sp_tab = "yzafpnum kMGTPEZY" 

90 sp_list, sp_pow = zip(*[(p, (idx - 8) * 3.0) for idx, p in enumerate(sp_tab) if p in select + " "]) 

91 idx = bisect.bisect(sp_pow, np.log10(abs(value)) + lztol) 

92 idx = max(idx - 1, 0) 

93 

94 return sp_list[idx].strip(), 10.0 ** sp_pow[idx] 

95 

96 

97def check_dir(filename): 

98 """Ensure the parent directory of a file path exists. 

99 

100 Parameters 

101 ---------- 

102 filename : str 

103 

104 The file path whose parent directory should be checked/created. 

105 

106 Returns 

107 ------- 

108 bool 

109 ``True`` if the directory already existed, ``False`` if it was created 

110 by this call. 

111 

112 Notes 

113 ----- 

114 This helper does not create the file itself; it only ensures that the 

115 directory component of ``filename`` exists. If ``filename`` has no 

116 directory component (e.g., ``"file.txt"``), this function returns ``True`` 

117 and performs no action. 

118 """ 

119 

120 dirname = os.path.dirname(filename) 

121 if dirname and not os.path.exists(dirname): 

122 os.makedirs(dirname) 

123 return False 

124 else: 

125 return True