Hide keyboard shortcuts

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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

# This file is part of daf_butler. 

# 

# Developed for the LSST Data Management System. 

# This product includes software developed by the LSST Project 

# (http://www.lsst.org). 

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

# for details of code ownership. 

# 

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

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

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

# (at your option) any later version. 

# 

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

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

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

# GNU General Public License for more details. 

# 

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

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

 

"""Support for assembling and disassembling afw Exposures.""" 

 

# Need to enable PSFs to be instantiated 

import lsst.afw.detection # noqa F401 

from lsst.afw.image import makeExposure, makeMaskedImage 

 

from lsst.daf.butler import CompositeAssembler 

 

 

class ExposureAssembler(CompositeAssembler): 

 

EXPOSURE_COMPONENTS = set(("image", "variance", "mask", "wcs", "psf")) 

EXPOSURE_INFO_COMPONENTS = set(("apCorrMap", "coaddInputs", "calib", "metadata", 

"filter", "transmissionCurve", "visitInfo")) 

 

def _groupRequestedComponents(self): 

"""Group requested components into top level and ExposureInfo. 

 

Returns 

------- 

expComps : `dict` 

Components associated with the top level Exposure. 

expInfoComps : `dict` 

Components associated with the ExposureInfo 

 

Raises 

------ 

ValueError 

There are components defined in the storage class that are not 

expected by this assembler. 

""" 

requested = set(self.storageClass.components.keys()) 

 

# Check that we are requesting something that we support 

unknown = requested - (self.EXPOSURE_COMPONENTS | self.EXPOSURE_INFO_COMPONENTS) 

57 ↛ 58line 57 didn't jump to line 58, because the condition on line 57 was never true if unknown: 

raise ValueError("Asking for unrecognized component: {}".format(unknown)) 

 

expItems = requested & self.EXPOSURE_COMPONENTS 

expInfoItems = requested & self.EXPOSURE_INFO_COMPONENTS 

return expItems, expInfoItems 

 

def getComponent(self, composite, componentName): 

"""Get a component from an Exposure 

 

Parameters 

---------- 

composite : `Exposure` 

`Exposure` to access component. 

componentName : `str` 

Name of component to retrieve. 

 

Returns 

------- 

component : `object` 

The component. Can be None. 

 

Raises 

------ 

AttributeError 

The component can not be found. 

""" 

if componentName in self.EXPOSURE_COMPONENTS: 

return super().getComponent(composite, componentName) 

86 ↛ 94line 86 didn't jump to line 94, because the condition on line 86 was never false elif componentName in self.EXPOSURE_INFO_COMPONENTS: 

if hasattr(composite, "getInfo"): 

# it is possible for this method to be called with 

# an ExposureInfo composite so trap for that and only get 

# the ExposureInfo if the method is supported 

composite = composite.getInfo() 

return super().getComponent(composite, componentName) 

else: 

raise AttributeError("Do not know how to retrieve component {} from {}".format(componentName, 

type(composite))) 

 

def getValidComponents(self, composite): 

"""Extract all non-None components from a composite. 

 

Parameters 

---------- 

composite : `object` 

Composite from which to extract components. 

 

Returns 

------- 

comps : `dict` 

Non-None components extracted from the composite, indexed by the 

component name as derived from the `self.storageClass`. 

""" 

# For Exposure we call the generic version twice: once for top level 

# components, and again for ExposureInfo. 

expItems, expInfoItems = self._groupRequestedComponents() 

 

components = super().getValidComponents(composite) 

infoComps = super().getValidComponents(composite.getInfo()) 

components.update(infoComps) 

return components 

 

def disassemble(self, composite): 

"""Disassemble an afw Exposure. 

 

This implementation attempts to extract components from the parent 

by looking for attributes of the same name or getter methods derived 

from the component name. 

 

Parameters 

---------- 

composite : `lsst.afw.Exposure` 

`Exposure` composite object consisting of components to be 

extracted. 

 

Returns 

------- 

components : `dict` 

`dict` with keys matching the components defined in 

`self.storageClass` and values being `DatasetComponent` instances 

describing the component. 

 

Raises 

------ 

ValueError 

A requested component can not be found in the parent using generic 

lookups. 

TypeError 

The parent object does not match the supplied `self.storageClass`. 

""" 

148 ↛ 149line 148 didn't jump to line 149, because the condition on line 148 was never true if not self.storageClass.validateInstance(composite): 

raise TypeError("Unexpected type mismatch between parent and StorageClass" 

" ({} != {})".format(type(composite), self.storageClass.pytype)) 

 

# Only look for components that are defined by the StorageClass 

components = {} 

expItems, expInfoItems = self._groupRequestedComponents() 

 

fromExposure = super().disassemble(composite, subset=expItems) 

components.update(fromExposure) 

 

fromExposureInfo = super().disassemble(composite, 

subset=expInfoItems, override=composite.getInfo()) 

components.update(fromExposureInfo) 

 

return components 

 

def assemble(self, components): 

"""Construct an Exposure from components. 

 

Parameters 

---------- 

components : `dict` 

All the components from which to construct the Exposure. 

Some can be missing. 

 

Returns 

------- 

exposure : `~lsst.afw.image.Exposure` 

Assembled exposure. 

 

Raises 

------ 

ValueError 

Some supplied components are not recognized. 

""" 

components = components.copy() 

maskedImageComponents = {} 

hasMaskedImage = False 

for component in ("image", "variance", "mask"): 

value = None 

if component in components: 

hasMaskedImage = True 

value = components.pop(component) 

maskedImageComponents[component] = value 

 

wcs = None 

195 ↛ 198line 195 didn't jump to line 198, because the condition on line 195 was never false if "wcs" in components: 

wcs = components.pop("wcs") 

 

pytype = self.storageClass.pytype 

199 ↛ 208line 199 didn't jump to line 208, because the condition on line 199 was never false if hasMaskedImage: 

maskedImage = makeMaskedImage(**maskedImageComponents) 

exposure = makeExposure(maskedImage, wcs=wcs) 

 

203 ↛ 204line 203 didn't jump to line 204, because the condition on line 203 was never true if not isinstance(exposure, pytype): 

raise RuntimeError("Unexpected type created in assembly;" 

" was {} expected {}".format(type(exposure), pytype)) 

 

else: 

exposure = pytype() 

if wcs is not None: 

exposure.setWcs(wcs) 

 

# Set other components 

exposure.setPsf(components.pop("psf", None)) 

exposure.setCalib(components.pop("calib", None)) 

 

info = exposure.getInfo() 

if "visitInfo" in components: 

info.setVisitInfo(components.pop("visitInfo")) 

info.setApCorrMap(components.pop("apCorrMap", None)) 

info.setCoaddInputs(components.pop("coaddInputs", None)) 

info.setMetadata(components.pop("metadata", None)) 

 

# If we have some components left over that is a problem 

224 ↛ 225line 224 didn't jump to line 225, because the condition on line 224 was never true if components: 

raise ValueError("The following components were not understood:" 

" {}".format(list(components.keys()))) 

 

return exposure 

 

def handleParameters(self, inMemoryDataset, parameters=None): 

"""Modify the in-memory dataset using the supplied parameters, 

returning a possibly new object. 

 

Parameters 

---------- 

inMemoryDataset : `object` 

Object to modify based on the parameters. 

parameters : `dict`, optional 

Parameters to apply. Values are specific to the parameter. 

Supported parameters are defined in the associated 

`StorageClass`. If no relevant parameters are specified the 

inMemoryDataset will be return unchanged. 

 

Returns 

------- 

inMemoryDataset : `object` 

Updated form of supplied in-memory dataset, after parameters 

have been used. 

""" 

# Understood by *this* subset command 

understood = ("bbox", "origin") 

use = self.storageClass.filterParameters(parameters, subset=understood) 

if use: 

inMemoryDataset = inMemoryDataset.subset(**use) 

 

return inMemoryDataset