Coverage for tests/qg_test_utils.py: 60%

62 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-24 03:18 -0700

1# This file is part of ctrl_bps. 

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"""QuantumGraph-related utilities to support ctrl_bps testing. 

22""" 

23 

24# Not actually running Quantum so do not need to override 'run' Method 

25# pylint: disable=abstract-method 

26 

27# Many dummy classes for testing. 

28# pylint: disable=missing-class-docstring 

29 

30import lsst.pipe.base.connectionTypes as cT 

31from lsst.daf.butler import Config, DataCoordinate, DatasetRef, DatasetType, DimensionUniverse, Quantum 

32from lsst.pex.config import Field 

33from lsst.pipe.base import PipelineTask, PipelineTaskConfig, PipelineTaskConnections, QuantumGraph, TaskDef 

34from lsst.utils.introspection import get_full_type_name 

35 

36METADATA = {"D1": [1, 2, 3]} 

37 

38 

39# For each dummy task, create a Connections, Config, and PipelineTask 

40 

41 

42class Dummy1Connections(PipelineTaskConnections, dimensions=("D1", "D2")): 

43 initOutput = cT.InitOutput(name="Dummy1InitOutput", storageClass="ExposureF", doc="n/a") 

44 input = cT.Input(name="Dummy1Input", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

45 output = cT.Output(name="Dummy1Output", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

46 

47 

48class Dummy1Config(PipelineTaskConfig, pipelineConnections=Dummy1Connections): 

49 conf1 = Field(dtype=int, default=1, doc="dummy config") 

50 

51 

52class Dummy1PipelineTask(PipelineTask): 

53 ConfigClass = Dummy1Config 

54 

55 

56class Dummy2Connections(PipelineTaskConnections, dimensions=("D1", "D2")): 

57 initInput = cT.InitInput(name="Dummy1InitOutput", storageClass="ExposureF", doc="n/a") 

58 initOutput = cT.InitOutput(name="Dummy2InitOutput", storageClass="ExposureF", doc="n/a") 

59 input = cT.Input(name="Dummy1Output", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

60 output = cT.Output(name="Dummy2Output", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

61 

62 

63class Dummy2Config(PipelineTaskConfig, pipelineConnections=Dummy2Connections): 

64 conf1 = Field(dtype=int, default=1, doc="dummy config") 

65 

66 

67class Dummy2PipelineTask(PipelineTask): 

68 ConfigClass = Dummy2Config 

69 

70 

71class Dummy3Connections(PipelineTaskConnections, dimensions=("D1", "D2")): 

72 initInput = cT.InitInput(name="Dummy2InitOutput", storageClass="ExposureF", doc="n/a") 

73 initOutput = cT.InitOutput(name="Dummy3InitOutput", storageClass="ExposureF", doc="n/a") 

74 input = cT.Input(name="Dummy2Output", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

75 output = cT.Output(name="Dummy3Output", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

76 

77 

78class Dummy3Config(PipelineTaskConfig, pipelineConnections=Dummy3Connections): 

79 conf1 = Field(dtype=int, default=1, doc="dummy config") 

80 

81 

82class Dummy3PipelineTask(PipelineTask): 

83 ConfigClass = Dummy3Config 

84 

85 

86# Test if a Task that does not interact with the other Tasks works fine in 

87# the graph. 

88class Dummy4Connections(PipelineTaskConnections, dimensions=("D1", "D2")): 

89 input = cT.Input(name="Dummy4Input", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

90 output = cT.Output(name="Dummy4Output", storageClass="ExposureF", doc="n/a", dimensions=("D1", "D2")) 

91 

92 

93class Dummy4Config(PipelineTaskConfig, pipelineConnections=Dummy4Connections): 

94 conf1 = Field(dtype=int, default=1, doc="dummy config") 

95 

96 

97class Dummy4PipelineTask(PipelineTask): 

98 ConfigClass = Dummy4Config 

99 

100 

101def make_test_quantum_graph(): 

102 """Create a QuantumGraph for unit tests. 

103 

104 Returns 

105 ------- 

106 qgraph : `lsst.pipe.base.QuantumGraph` 

107 A test QuantumGraph looking like the following: 

108 (DummyTask4 is completely independent.) 

109 

110 Numbers in parens are the values for the two dimensions (D1, D2). 

111 

112 T1(1,2) T1(3,4) T4(1,2) T4(3,4) 

113 | | 

114 T2(1,2) T2(3,4) 

115 | | 

116 T3(1,2) T3(3,4) 

117 """ 

118 config = Config( 

119 { 

120 "version": 1, 

121 "skypix": { 

122 "common": "htm7", 

123 "htm": { 

124 "class": "lsst.sphgeom.HtmPixelization", 

125 "max_level": 24, 

126 }, 

127 }, 

128 "elements": { 

129 "D1": { 

130 "keys": [ 

131 { 

132 "name": "id", 

133 "type": "int", 

134 } 

135 ], 

136 "storage": { 

137 "cls": "lsst.daf.butler.registry.dimensions.table.TableDimensionRecordStorage", 

138 }, 

139 }, 

140 "D2": { 

141 "keys": [ 

142 { 

143 "name": "id", 

144 "type": "int", 

145 } 

146 ], 

147 "storage": { 

148 "cls": "lsst.daf.butler.registry.dimensions.table.TableDimensionRecordStorage", 

149 }, 

150 }, 

151 }, 

152 "packers": {}, 

153 } 

154 ) 

155 

156 universe = DimensionUniverse(config=config) 

157 # need to make a mapping of TaskDef to set of quantum 

158 quantum_map = {} 

159 tasks = [] 

160 for task, label in ( 

161 (Dummy1PipelineTask, "T1"), 

162 (Dummy2PipelineTask, "T2"), 

163 (Dummy3PipelineTask, "T3"), 

164 (Dummy4PipelineTask, "T4"), 

165 ): 

166 task_def = TaskDef(get_full_type_name(task), task.ConfigClass(), task, label) 

167 tasks.append(task_def) 

168 quantum_set = set() 

169 for dim1, dim2 in ((1, 2), (3, 4)): 

170 if task_def.connections.initInputs: 

171 init_init_ds_type = DatasetType( 

172 task_def.connections.initInput.name, 

173 tuple(), 

174 storageClass=task_def.connections.initInput.storageClass, 

175 universe=universe, 

176 ) 

177 init_refs = [DatasetRef(init_init_ds_type, DataCoordinate.makeEmpty(universe))] 

178 else: 

179 init_refs = None 

180 input_ds_type = DatasetType( 

181 task_def.connections.input.name, 

182 task_def.connections.input.dimensions, 

183 storageClass=task_def.connections.input.storageClass, 

184 universe=universe, 

185 ) 

186 input_refs = [ 

187 DatasetRef( 

188 input_ds_type, DataCoordinate.standardize({"D1": dim1, "D2": dim2}, universe=universe) 

189 ) 

190 ] 

191 output_ds_type = DatasetType( 

192 task_def.connections.output.name, 

193 task_def.connections.output.dimensions, 

194 storageClass=task_def.connections.output.storageClass, 

195 universe=universe, 

196 ) 

197 output_refs = [ 

198 DatasetRef( 

199 output_ds_type, DataCoordinate.standardize({"D1": dim1, "D2": dim2}, universe=universe) 

200 ) 

201 ] 

202 quantum_set.add( 

203 Quantum( 

204 taskName=task.__qualname__, 

205 dataId=DataCoordinate.standardize({"D1": dim1, "D2": dim2}, universe=universe), 

206 taskClass=task, 

207 initInputs=init_refs, 

208 inputs={input_ds_type: input_refs}, 

209 outputs={output_ds_type: output_refs}, 

210 ) 

211 ) 

212 quantum_map[task_def] = quantum_set 

213 qgraph = QuantumGraph(quantum_map, metadata=METADATA) 

214 

215 return qgraph