Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-5922: Rework camera geometry to use the replacement for XYTransform #36

Merged
merged 5 commits into from
Sep 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
_build.*
.sconsign.dblite
.cache
config.log
.sconf_temp
*.o
Expand Down
34 changes: 19 additions & 15 deletions bin/genCameraRepository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
WARNING: this code is deprecated because it generates incorrect overscan;
see DM-5524 which fixed the problem by editing the generated amp info catalogs directly.

WARNING: this code is broken. See DM-11560.

Example:

python bin/genCameraRepository.py megacam/Full_Megacam_geom.paf megacam/camera
Expand All @@ -19,11 +21,11 @@
import lsst.pex.policy as pexPolicy
import lsst.afw.table as afwTable
import lsst.afw.geom as afwGeom
from lsst.afw.cameraGeom import SCIENCE, FOCAL_PLANE, PUPIL, CameraConfig, DetectorConfig,\
from lsst.afw.cameraGeom import SCIENCE, FOCAL_PLANE, FIELD_ANGLE, CameraConfig, DetectorConfig,\
makeCameraFromCatalogs, NullLinearityType
from lsst.obs.cfht import MegacamMapper

PIXELSIZE = 0.0135 #mm/pix
PIXELSIZE = 0.0135 # mm/pix


def makeCameraFromPolicy(filename, writeRepo=False, outputDir=None, doClobber=False, ccdToUse=None,
Expand All @@ -38,7 +40,7 @@ def makeCameraFromPolicy(filename, writeRepo=False, outputDir=None, doClobber=Fa
@param shortNameMethod: Method to compactify ccd names into names easily used in paths
@return Camera object
"""
#This is all fragile as the CameraGeomDictionary.paf will go away.
# This is all fragile as the CameraGeomDictionary.paf will go away.
policyFile = pexPolicy.DefaultPolicyFile("afw", "CameraGeomDictionary.paf", "policy")
defPolicy = pexPolicy.Policy.createPolicy(policyFile, policyFile.getRepositoryPath(), True)

Expand Down Expand Up @@ -100,7 +102,7 @@ def parseCamera(policy):
camConfig.name = camPolicy.get('name')
# Using pixel scale 0.185 arcsec/pixel from:
# http://arxiv.org/pdf/0908.3808v1.pdf
camConfig.plateScale = 13.70 #arcsec/mm
camConfig.plateScale = 13.70 # arcsec/mm

# Radial distortion correction polynomial coeff.
conv_1 = 14805.4
Expand All @@ -109,15 +111,15 @@ def parseCamera(policy):

tConfig = afwGeom.TransformConfig()
tConfig.transform.name = 'inverted'
radialClass = afwGeom.xyTransformRegistry['radial']
radialClass = afwGeom.transformRegistry['radial']
tConfig.transform.active.transform.retarget(radialClass)

coeffs = [0., conv_1, conv_2, conv_3]
tConfig.transform.active.transform.coeffs = coeffs

tmc = afwGeom.TransformMapConfig()
tmc.nativeSys = FOCAL_PLANE.getSysName()
tmc.transforms = {PUPIL.getSysName(): tConfig}
tmc.transforms = {FIELD_ANGLE.getSysName(): tConfig}
camConfig.transformDict = tmc
return camConfig

Expand Down Expand Up @@ -149,8 +151,8 @@ def makeCcdParams(policy, ampParms):
for ccd in policy.getArray('Ccd'):
ptype = ccd.get('ptype')
tdict = {}
#The policy file has units of pixels, but to get to
#pupil coords we need to work in units of mm
# The policy file has units of pixels, but to get to
# FIELD_ANGLE coords we need to work in units of mm
tdict['pixelSize'] = PIXELSIZE
tdict['offsetUnit'] = 'mm'
tdict['ampArr'] = []
Expand All @@ -161,11 +163,11 @@ def makeCcdParams(policy, ampParms):
ampType = amp.get('ptype')
parms = copy.copy(ampParms[ampType])
xsize += parms['datasec'][2] - parms['datasec'][0] + 1
#I think the megacam chips only have a single row of amps
# I think the megacam chips only have a single row of amps
ysize = parms['datasec'][3] - parms['datasec'][1] + 1
parms['id'] = amp.get('serial')
parms['flipX'] = amp.get('flipLR')
#As far as I know there is no bilateral symmetry in megacam
# As far as I know there is no bilateral symmetry in megacam
parms['flipY'] = False
tdict['ampArr'].append(parms)
tdict['xsize'] = xsize
Expand Down Expand Up @@ -228,8 +230,8 @@ def addAmp(ampCatalog, amp, eparams):
afwGeom.Extent2I(dataSec.getDimensions().getX(), pscan))

if amp['flipX']:
#No need to flip bbox or allPixels since they
#are at the origin and span the full pixel grid
# No need to flip bbox or allPixels since they
# are at the origin and span the full pixel grid
biasSec.flipLR(xtot)
dataSec.flipLR(xtot)
voscanSec.flipLR(xtot)
Expand All @@ -247,7 +249,7 @@ def addAmp(ampCatalog, amp, eparams):

record.setBBox(bbox)
record.setRawXYOffset(afwGeom.ExtentI(0, 0))
#Set amplifier names according to the CFHT convention (A, B)
# Set amplifier names according to the CFHT convention (A, B)
if eparams['index'][0] == 0 and eparams['index'][1] == 0:
record.setName("A")
elif eparams['index'][0] == 1 and eparams['index'][1] == 0:
Expand All @@ -259,7 +261,7 @@ def addAmp(ampCatalog, amp, eparams):
record.setReadNoise(eparams['readNoise'])
record.setSaturation(eparams['saturation'])
record.setSuspectLevel(float("nan")) # SUSPECT level unknown
#The files do not have any linearity information
# The files do not have any linearity information
record.setLinearityType(NullLinearityType)
record.setLinearityCoeffs([1., ])
record.setHasRawInfo(True)
Expand Down Expand Up @@ -332,6 +334,7 @@ def parseCcds(policy, ccdParams, ccdToUse=None):
ccdInfoList.append(detConfig)
return {"ccdInfo": ccdInfoList, "ampInfo": ampInfoDict}


if __name__ == "__main__":
print("WARNING: this code generates incorrect vertical overscan; see DM-5524")
baseDir = eups.productDir("obs_cfht")
Expand All @@ -344,4 +347,5 @@ def parseCcds(policy, ccdParams, ccdToUse=None):
args = parser.parse_args()

camera = makeCameraFromPolicy(args.LayoutPolicy, writeRepo=True, outputDir=args.OutputDir,
ccdToUse='bottom', doClobber=args.clobber, shortNameMethod=MegacamMapper.getShortCcdName)
ccdToUse='bottom', doClobber=args.clobber,
shortNameMethod=MegacamMapper.getShortCcdName)
54 changes: 29 additions & 25 deletions bin/genDefects.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os, sys
import os
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

import lsst.afw.image as afwImage
Expand All @@ -8,7 +8,8 @@

import numpy as np

def makeBBList(mask, ccd) :

def makeBBList(mask, ccd):

# Create a bounding box corresponding to the useful part of the CCD (exclude overscan regions)
bb = afwGeom.Box2I(afwGeom.Point2I(32, 0), afwGeom.Point2I(2079, 4611))
Expand All @@ -29,7 +30,7 @@ def makeBBList(mask, ccd) :
for f in s.getFootprints():
fpl = afwDetect.footprintToBBoxList(f)
for i in fpl:
i.shift(afwGeom.Extent2I(-32,0))
i.shift(afwGeom.Extent2I(-32, 0))

x0 = i.getBeginX()
y0 = i.getBeginY()
Expand All @@ -40,29 +41,29 @@ def makeBBList(mask, ccd) :
defect['w'].append(w0)
defect['h'].append(h0)

if (x0 % 2 == 0) :
if (x0 % 2 == 0):
x1 = x0
if (w0 % 2 == 0) :
if (w0 % 2 == 0):
w1 = w0
else :
else:
w1 = w0 + 1
else :
else:
x1 = max(x0 - 1, 0)
if (w0 % 2 == 0) :
if (w0 % 2 == 0):
w1 = min(w0 + 2, 2048)
else :
else:
w1 = min(w0 + 1, 2048)
if (y0 % 2 == 0):
y1 = y0
if (h0 % 2 == 0) :
if (h0 % 2 == 0):
h1 = h0
else :
else:
h1 = min(h0 + 1, 4612)
else :
else:
y1 = max(y0 - 1, 0)
if (h0 % 2 == 0) :
if (h0 % 2 == 0):
h1 = min(h0 + 2, 4612)
else :
else:
h1 = min(h0 + 1, 4612)

defectE['x'].append(x1)
Expand All @@ -72,15 +73,16 @@ def makeBBList(mask, ccd) :

return defect, defectE

def writeFits(ccd, defect, fileOut) :

ccdSerial = ['834175', '835234', '8352153', '8261144', '8341174', '8351205',
'8351133', '835163', '8261133', '917213', '835244', '8352155',
'8351204', '8351173', '8434135', '8341173', '8351114', '7432193',
'917243', '8341165', '8352134', '8374175', '8351115', '835164',
'8351185', '8352185', '835173', '8261165', '743233', '8351164',
'8261195', '835183', '8352104', '8352154', '826173', '8261143',
'917224', '835264', '835235', '8261155']
def writeFits(ccd, defect, fileOut):

ccdSerial = ['834175', '835234', '8352153', '8261144', '8341174', '8351205',
'8351133', '835163', '8261133', '917213', '835244', '8352155',
'8351204', '8351173', '8434135', '8341173', '8351114', '7432193',
'917243', '8341165', '8352134', '8374175', '8351115', '835164',
'8351185', '8352185', '835173', '8261165', '743233', '8351164',
'8261195', '835183', '8352104', '8352154', '826173', '8261143',
'917224', '835264', '835235', '8261155']

col1 = fits.Column(name="x0", format="I", array=np.asarray(defect['x']))
col2 = fits.Column(name="y0", format="I", array=np.asarray(defect['y']))
Expand All @@ -96,7 +98,8 @@ def writeFits(ccd, defect, fileOut) :

return

def main(argv=None) :

def main(argv=None):

description = """Transforms Elixir defect masks to LSST format"""
prog = "genDefects.py"
Expand All @@ -108,7 +111,7 @@ def main(argv=None) :
parser.add_argument('--numccd', default=36, type=int, help='Number of CCD')
args = parser.parse_args(argv)

if args.numccd != 36 :
if args.numccd != 36:
print("Warning : LSST DM stack knows about 36 CCD only")

dir1 = args.mask + ".nn"
Expand All @@ -118,11 +121,12 @@ def main(argv=None) :
if not os.path.exists(dir2):
os.makedirs(dir2)

for ccd in range(args.numccd) :
for ccd in range(args.numccd):
print("Computing masks for ccd %i"%ccd)
defect, defectE = makeBBList(args.mask, ccd)
writeFits(ccd, defect, os.path.join(dir1, 'ccd%02i'%ccd + '.fits'))
writeFits(ccd, defectE, os.path.join(dir2, 'ccd%02i'%ccd + '.fits'))


if __name__ == "__main__":
main()
4 changes: 3 additions & 1 deletion bin/megacamCalibRegistry.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ def parseDetrendDatabase(tableName, create=False):
conn.commit()

# Parse FITS table into sqlite
convertUnixTime = lambda time: datetime.datetime.fromtimestamp(time).isoformat()
def convertUnixTime(time):
return datetime.datetime.fromtimestamp(time).isoformat()
fits = pyfits.open(tableName)
table = fits[1].data
for row in table:
Expand Down Expand Up @@ -124,6 +125,7 @@ def parseDetrendDatabase(tableName, create=False):
conn.commit()
conn.close()


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Parse the CFHT Elixir detrend database to create " +
"a calibration registry")
Expand Down
25 changes: 12 additions & 13 deletions megacam/camera/camera.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!!!!This file is auto generated.----Do not edit!!!!
#!!!!Edit input file and regenerate with $OBS_CFHT_DIR/bin/genCameraRepository.py
# At one time this file was auto-generated by bin/genCameraRepository.py
# However, that script is broken (see DM-11560) and this file
# is manually maintained, at least until that ticket is fixed.
import lsst.afw.cameraGeom.cameraConfig
assert type(config) == lsst.afw.cameraGeom.cameraConfig.CameraConfig, 'config is of type %s.%s instead of lsst.afw.cameraGeom.cameraConfig.CameraConfig' % (
type(config).__module__, type(config).__name__)
Expand All @@ -10,26 +11,24 @@
config.transformDict.nativeSys = 'FocalPlane'

config.transformDict.transforms = {}
config.transformDict.transforms['Pupil'] = lsst.afw.geom.transformConfig.TransformConfig()
config.transformDict.transforms['Pupil'].transform['multi'].transformDict = None
config.transformDict.transforms['FieldAngle'] = lsst.afw.geom.transformConfig.TransformConfig()
config.transformDict.transforms['FieldAngle'].transform['multi'].transformDict = None
# x, y translation vector
config.transformDict.transforms['Pupil'].transform['affine'].translation = [0.0, 0.0]
config.transformDict.transforms['FieldAngle'].transform['affine'].translation = [0.0, 0.0]

# 2x2 linear matrix in the usual numpy order;
# to rotate a vector by theta use: cos(theta), sin(theta), -sin(theta), cos(theta)
config.transformDict.transforms['Pupil'].transform['affine'].linear = [1.0, 0.0, 0.0, 1.0]
config.transformDict.transforms['FieldAngle'].transform['affine'].linear = [1.0, 0.0, 0.0, 1.0]

# Coefficients for the radial polynomial; coeff[0] must be 0
config.transformDict.transforms['Pupil'].transform['radial'].coeffs = None

import lsst.afw.geom.xyTransformFactory
config.transformDict.transforms['Pupil'].transform['inverted'].transform.retarget(
target=lsst.afw.geom.xyTransformFactory.makeRadialXYTransform, ConfigClass=lsst.afw.geom.xyTransformFactory.RadialXYTransformConfig)
config.transformDict.transforms['FieldAngle'].transform['radial'].coeffs = None
config.transformDict.transforms['FieldAngle'].transform['inverted'
].transform.retarget(target=lsst.afw.geom.transformRegistry['radial'])
# Coefficients for the radial polynomial; coeff[0] must be 0
config.transformDict.transforms['Pupil'].transform[
config.transformDict.transforms['FieldAngle'].transform[
'inverted'].transform.coeffs = [0.0, 14805.4, 13619.3, 426637.0]

config.transformDict.transforms['Pupil'].transform.name = 'inverted'
config.transformDict.transforms['FieldAngle'].transform.name = 'inverted'
config.detectorList = {}
config.detectorList[0] = lsst.afw.cameraGeom.cameraConfig.DetectorConfig()
# y0 of pixel bounding box
Expand Down
3 changes: 2 additions & 1 deletion python/lsst/obs/cfht/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import re

from lsst.pipe.tasks.ingest import ParseTask
import lsst.pex.exceptions

filters = {'u.MP9301': 'u',
'u.MP9302': 'u2',
Expand Down Expand Up @@ -66,7 +67,7 @@ def translate_defects(self, md):
maskName = md.get("IMRED_MK").strip()
maskName, ccd = maskName.split(".fits")
filter = md.get("FILTER").strip().split('.')[0]
if filter in [ "i", "i2", "i3", "z", "z2"]:
if filter in ["i", "i2", "i3", "z", "z2"]:
maskName = maskName+"_enlarged"
maskFile = maskName+".nn/"+ccd[1:6]+".fits"
return maskFile
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.