LSSTApplications  17.0+103,17.0+11,17.0+61,18.0.0+13,18.0.0+25,18.0.0+5,18.0.0+52,18.0.0-4-g68ffd23,18.1.0-1-g0001055+8,18.1.0-1-g03d53ef+1,18.1.0-1-g1349e88+28,18.1.0-1-g2505f39+22,18.1.0-1-g380d4d4+27,18.1.0-1-g5315e5e+1,18.1.0-1-g5e4b7ea+10,18.1.0-1-g7e8fceb+1,18.1.0-1-g85f8cd4+23,18.1.0-1-g9a6769a+13,18.1.0-1-ga1a4c1a+22,18.1.0-1-gd55f500+17,18.1.0-12-g42eabe8e+10,18.1.0-14-gd04256d+15,18.1.0-16-g430f6a53+1,18.1.0-17-gd2166b6e4,18.1.0-18-gb5d19ff+1,18.1.0-2-gfbf3545+7,18.1.0-2-gfefb8b5+16,18.1.0-3-g52aa583+13,18.1.0-3-g62b5e86+14,18.1.0-3-g8f4a2b1+17,18.1.0-3-g9bc06b8+7,18.1.0-3-gb69f684+9,18.1.0-4-g1ee41a7+1,18.1.0-5-g6dbcb01+13,18.1.0-5-gc286bb7+3,18.1.0-6-g48bdcd3+2,18.1.0-6-gd05e160+9,18.1.0-7-gc4d902b+2,18.1.0-7-gebc0338+8,18.1.0-9-gae7190a+10,w.2019.38
LSSTDataManagementBasePackage
Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask Class Reference

Basic implemeentation of the astrometry.net astrometrical fitter. More...

Inheritance diagram for lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask:

Public Member Functions

def __init__ (self, config, andConfig=None, kwargs)
 Construct an ANetBasicAstrometryTask. More...
 
def memusage (self, prefix='')
 
def useKnownWcs (self, sourceCat, wcs=None, exposure=None, filterName=None, bbox=None, calculateSip=None)
 Return an InitialAstrometry object, just like determineWcs, but assuming the given input WCS is correct. More...
 
def determineWcs (self, sourceCat, exposure, kwargs)
 
def determineWcs2 (self, sourceCat, kwargs)
 
def getBlindWcsSolution (self, sourceCat, exposure=None, wcs=None, bbox=None, radecCenter=None, searchRadius=None, pixelScale=None, filterName=None, doTrim=False, usePixelScale=True, useRaDecCenter=True, useParity=True, searchRadiusScale=2.)
 
def getSipWcsFromWcs (self, wcs, bbox, ngrid=20, linearizeAtCenter=True)
 Get a TAN-SIP WCS, starting from an existing WCS. More...
 
def getSipWcsFromCorrespondences (self, origWcs, refCat, sourceCat, bbox)
 
def plotSolution (self, matches, wcs, imageSize)
 
def getColumnName (self, filterName, columnMap, default=None)
 

Public Attributes

 config
 
 refObjLoader
 

Static Public Attributes

 ConfigClass = ANetBasicAstrometryConfig
 

Detailed Description

Basic implemeentation of the astrometry.net astrometrical fitter.

A higher-level class ANetAstrometryTask takes care of dealing with the fact that the initial WCS is probably only a pure TAN SIP, yet we may have significant distortion and a good estimate for that distortion.

About Astrometry.net index files (astrometry_net_data):

There are three components of an index file: a list of stars (stored as a star kd-tree), a list of quadrangles of stars ("quad file") and a list of the shapes ("codes") of those quadrangles, stored as a code kd-tree.

Each index covers a region of the sky, defined by healpix nside and number, and a range of angular scales. In LSST, we share the list of stars in a part of the sky between multiple indexes. That is, the star kd-tree is shared between multiple indices (quads and code kd-trees). In the astrometry.net code, this is called a "multiindex".

It is possible to "unload" and "reload" multiindex (and index) objects. When "unloaded", they consume no FILE or mmap resources.

The multiindex object holds the star kd-tree and gives each index object it holds a pointer to it, so it is necessary to multiindex_reload_starkd() before reloading the indices it holds. The multiindex_unload() method, on the other hand, unloads its starkd and unloads each index it holds.

Definition at line 216 of file anetBasicAstrometry.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.__init__ (   self,
  config,
  andConfig = None,
  kwargs 
)

Construct an ANetBasicAstrometryTask.

Parameters
[in]configconfiguration (an instance of self.ConfigClass)
[in]andConfigastrometry.net data config (an instance of AstromNetDataConfig, or None); if None then use andConfig.py in the astrometry_net_data product (which must be setup)
[in]kwargsadditional keyword arguments for pipe_base Task.__init__
Exceptions
RuntimeErrorif andConfig is None and the configuration cannot be found, either because astrometry_net_data is not setup in eups or because the setup version does not include the file "andConfig.py"

Definition at line 253 of file anetBasicAstrometry.py.

253  **kwargs):
254  r"""!Construct an ANetBasicAstrometryTask
255 
256  @param[in] config configuration (an instance of self.ConfigClass)
257  @param[in] andConfig astrometry.net data config (an instance of AstromNetDataConfig, or None);
258  if None then use andConfig.py in the astrometry_net_data product (which must be setup)
259  @param[in] kwargs additional keyword arguments for pipe_base Task.\_\_init\_\_
260 
261  @throw RuntimeError if andConfig is None and the configuration cannot be found,
262  either because astrometry_net_data is not setup in eups
263  or because the setup version does not include the file "andConfig.py"
264  """
265  pipeBase.Task.__init__(self, config=config, **kwargs)
266  self.config = config
267  # this is not a subtask because it cannot safely be retargeted
268  self.refObjLoader = LoadAstrometryNetObjectsTask(
269  config=self.config,
270  andConfig=andConfig,
271  log=self.log,
272  name="loadAN",
273  )
274  self.refObjLoader._readIndexFiles()
275 

Member Function Documentation

◆ determineWcs()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.determineWcs (   self,
  sourceCat,
  exposure,
  kwargs 
)
Find a WCS solution for the given 'sourceCat' in the given
'exposure', getting other parameters from config.

Valid kwargs include:

'radecCenter', an afw.geom.SpherePoint giving the ICRS RA,Dec position
   of the center of the field.  This is used to limit the
   search done by Astrometry.net (to make it faster and load
   fewer index files, thereby using less memory).  Defaults to
   the RA,Dec center from the exposure's WCS; turn that off
   with the boolean kwarg 'useRaDecCenter' or config option
   'useWcsRaDecCenter'

'useRaDecCenter', a boolean.  Don't use the RA,Dec center from
   the exposure's initial WCS.

'searchRadius', in degrees, to search for a solution around
   the given 'radecCenter'; default from config option
   'raDecSearchRadius'.

'useParity': parity is the 'flip' of the image.  Knowing it
   reduces the search space (hence time) for Astrometry.net.
   The parity can be computed from the exposure's WCS (the
   sign of the determinant of the CD matrix); this option
   controls whether we do that or force Astrometry.net to
   search both parities.  Default from config.useWcsParity.

'pixelScale': geom.Angle, estimate of the angle-per-pixel
   (ie, arcseconds per pixel).  Defaults to a value derived
   from the exposure's WCS.  If enabled, this value, plus or
   minus config.pixelScaleUncertainty, will be used to limit
   Astrometry.net's search.

'usePixelScale': boolean.  Use the pixel scale to limit
   Astrometry.net's search?  Defaults to config.useWcsPixelScale.

'filterName', a string, the filter name of this image.  Will
   be mapped through the 'filterMap' config dictionary to a
   column name in the astrometry_net_data index FITS files.
   Defaults to the exposure.getFilter() value.

'bbox', bounding box of exposure; defaults to exposure.getBBox()

Definition at line 403 of file anetBasicAstrometry.py.

403  def determineWcs(self, sourceCat, exposure, **kwargs):
404  """Find a WCS solution for the given 'sourceCat' in the given
405  'exposure', getting other parameters from config.
406 
407  Valid kwargs include:
408 
409  'radecCenter', an afw.geom.SpherePoint giving the ICRS RA,Dec position
410  of the center of the field. This is used to limit the
411  search done by Astrometry.net (to make it faster and load
412  fewer index files, thereby using less memory). Defaults to
413  the RA,Dec center from the exposure's WCS; turn that off
414  with the boolean kwarg 'useRaDecCenter' or config option
415  'useWcsRaDecCenter'
416 
417  'useRaDecCenter', a boolean. Don't use the RA,Dec center from
418  the exposure's initial WCS.
419 
420  'searchRadius', in degrees, to search for a solution around
421  the given 'radecCenter'; default from config option
422  'raDecSearchRadius'.
423 
424  'useParity': parity is the 'flip' of the image. Knowing it
425  reduces the search space (hence time) for Astrometry.net.
426  The parity can be computed from the exposure's WCS (the
427  sign of the determinant of the CD matrix); this option
428  controls whether we do that or force Astrometry.net to
429  search both parities. Default from config.useWcsParity.
430 
431  'pixelScale': geom.Angle, estimate of the angle-per-pixel
432  (ie, arcseconds per pixel). Defaults to a value derived
433  from the exposure's WCS. If enabled, this value, plus or
434  minus config.pixelScaleUncertainty, will be used to limit
435  Astrometry.net's search.
436 
437  'usePixelScale': boolean. Use the pixel scale to limit
438  Astrometry.net's search? Defaults to config.useWcsPixelScale.
439 
440  'filterName', a string, the filter name of this image. Will
441  be mapped through the 'filterMap' config dictionary to a
442  column name in the astrometry_net_data index FITS files.
443  Defaults to the exposure.getFilter() value.
444 
445  'bbox', bounding box of exposure; defaults to exposure.getBBox()
446 
447  """
448  assert(exposure is not None)
449 
450  margs = kwargs.copy()
451  if 'searchRadius' not in margs:
452  margs.update(searchRadius=self.config.raDecSearchRadius * geom.degrees)
453  if 'usePixelScale' not in margs:
454  margs.update(usePixelScale=self.config.useWcsPixelScale)
455  if 'useRaDecCenter' not in margs:
456  margs.update(useRaDecCenter=self.config.useWcsRaDecCenter)
457  if 'useParity' not in margs:
458  margs.update(useParity=self.config.useWcsParity)
459  margs.update(exposure=exposure)
460  return self.determineWcs2(sourceCat=sourceCat, **margs)
461 

◆ determineWcs2()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.determineWcs2 (   self,
  sourceCat,
  kwargs 
)
Get a blind astrometric solution for the given catalog of sources.

We need:
  -the image size;
  -the filter

And if available, we can use:
  -an initial Wcs estimate;
     --> RA,Dec center
     --> pixel scale
     --> "parity"

(all of which are metadata of Exposure).

filterName: string
imageSize: (W,H) integer tuple/iterable
pixelScale: lsst.geom.Angle per pixel.
radecCenter: lsst.afw.coord.Coord

Definition at line 462 of file anetBasicAstrometry.py.

462  def determineWcs2(self, sourceCat, **kwargs):
463  """Get a blind astrometric solution for the given catalog of sources.
464 
465  We need:
466  -the image size;
467  -the filter
468 
469  And if available, we can use:
470  -an initial Wcs estimate;
471  --> RA,Dec center
472  --> pixel scale
473  --> "parity"
474 
475  (all of which are metadata of Exposure).
476 
477  filterName: string
478  imageSize: (W,H) integer tuple/iterable
479  pixelScale: lsst.geom.Angle per pixel.
480  radecCenter: lsst.afw.coord.Coord
481  """
482  wcs, qa = self.getBlindWcsSolution(sourceCat, **kwargs)
483  kw = {}
484  # Keys passed to useKnownWcs
485  for key in ['exposure', 'bbox', 'filterName']:
486  if key in kwargs:
487  kw[key] = kwargs[key]
488  astrom = self.useKnownWcs(sourceCat, wcs=wcs, **kw)
489  astrom.solveQa = qa
490  astrom.tanWcs = wcs
491  return astrom
492 

◆ getBlindWcsSolution()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.getBlindWcsSolution (   self,
  sourceCat,
  exposure = None,
  wcs = None,
  bbox = None,
  radecCenter = None,
  searchRadius = None,
  pixelScale = None,
  filterName = None,
  doTrim = False,
  usePixelScale = True,
  useRaDecCenter = True,
  useParity = True,
  searchRadiusScale = 2. 
)

Definition at line 505 of file anetBasicAstrometry.py.

505  searchRadiusScale=2.):
506  if not useRaDecCenter and radecCenter is not None:
507  raise RuntimeError('radecCenter is set, but useRaDecCenter is False. Make up your mind!')
508  if not usePixelScale and pixelScale is not None:
509  raise RuntimeError('pixelScale is set, but usePixelScale is False. Make up your mind!')
510 
511  bbox, wcs, filterName = self._getImageParams(
512  exposure=exposure,
513  bbox=bbox,
514  wcs=wcs,
515  filterName=filterName,
516  wcsRequired=False,
517  )
518 
519  bboxD = geom.Box2D(bbox)
520  xc, yc = bboxD.getCenter()
521  parity = None
522 
523  if wcs is not None:
524  if pixelScale is None:
525  if usePixelScale:
526  pixelScale = wcs.getPixelScale()
527  self.log.debug('Setting pixel scale estimate = %.3f from given WCS estimate',
528  pixelScale.asArcseconds())
529 
530  if radecCenter is None:
531  if useRaDecCenter:
532  radecCenter = wcs.pixelToSky(xc, yc)
533  self.log.debug('Setting RA,Dec center estimate = (%.3f, %.3f) from given WCS '
534  'estimate, using pixel center = (%.1f, %.1f)',
535  radecCenter.getLongitude().asDegrees(),
536  radecCenter.getLatitude().asDegrees(), xc, yc)
537 
538  if searchRadius is None:
539  if useRaDecCenter:
540  assert(pixelScale is not None)
541  pixRadius = math.hypot(*bboxD.getDimensions()) / 2
542  searchRadius = (pixelScale * pixRadius * searchRadiusScale)
543  self.log.debug('Using RA,Dec search radius = %.3f deg, from pixel scale, '
544  'image size, and searchRadiusScale = %g',
545  searchRadius, searchRadiusScale)
546  if useParity:
547  parity = wcs.isFlipped
548  self.log.debug('Using parity = %s' % (parity and 'True' or 'False'))
549 
550  if doTrim:
551  n = len(sourceCat)
552  if exposure is not None:
553  exposureBBoxD = geom.Box2D(exposure.getMaskedImage().getBBox())
554  else:
555  exposureBBoxD = bboxD
556  sourceCat = self._trimBadPoints(sourceCat, exposureBBoxD)
557  self.log.debug("Trimming: kept %i of %i sources", n, len(sourceCat))
558 
559  wcs, qa = self._solve(
560  sourceCat=sourceCat,
561  wcs=wcs,
562  bbox=bbox,
563  pixelScale=pixelScale,
564  radecCenter=radecCenter,
565  searchRadius=searchRadius,
566  parity=parity,
567  filterName=filterName,
568  )
569  if wcs is None:
570  raise RuntimeError("Unable to match sources with catalog.")
571  self.log.info('Got astrometric solution from Astrometry.net')
572 
573  rdc = wcs.pixelToSky(xc, yc)
574  self.log.debug('New WCS says image center pixel (%.1f, %.1f) -> RA,Dec (%.3f, %.3f)',
575  xc, yc, rdc.getLongitude().asDegrees(), rdc.getLatitude().asDegrees())
576  return wcs, qa
577 
A floating-point coordinate rectangle geometry.
Definition: Box.h:305

◆ getColumnName()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.getColumnName (   self,
  filterName,
  columnMap,
  default = None 
)
Returns the column name in the astrometry_net_data index file that will be used
for the given filter name.

@param filterName   Name of filter used in exposure
@param columnMap    Dict that maps filter names to column names
@param default      Default column name

Definition at line 844 of file anetBasicAstrometry.py.

844  def getColumnName(self, filterName, columnMap, default=None):
845  """
846  Returns the column name in the astrometry_net_data index file that will be used
847  for the given filter name.
848 
849  @param filterName Name of filter used in exposure
850  @param columnMap Dict that maps filter names to column names
851  @param default Default column name
852  """
853  filterName = self.config.filterMap.get(filterName, filterName) # Exposure filter --> desired filter
854  try:
855  return columnMap[filterName] # Desired filter --> a_n_d column name
856  except KeyError:
857  self.log.warn("No column in configuration for filter '%s'; using default '%s'" %
858  (filterName, default))
859  return default
860 

◆ getSipWcsFromCorrespondences()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.getSipWcsFromCorrespondences (   self,
  origWcs,
  refCat,
  sourceCat,
  bbox 
)
Produce a SIP solution given a list of known correspondences.

Unlike _calculateSipTerms, this does not iterate the solution;
it assumes you have given it a good sets of corresponding stars.

NOTE that "refCat" and "sourceCat" are assumed to be the same length;
entries "refCat[i]" and "sourceCat[i]" are assumed to be correspondences.

@param[in] origWcs  the WCS to linearize in order to get the TAN part of the TAN-SIP WCS.
@param[in] refCat  reference source catalog
@param[in] sourceCat  source catalog
@param[in] bbox  bounding box of image

Definition at line 629 of file anetBasicAstrometry.py.

629  def getSipWcsFromCorrespondences(self, origWcs, refCat, sourceCat, bbox):
630  """Produce a SIP solution given a list of known correspondences.
631 
632  Unlike _calculateSipTerms, this does not iterate the solution;
633  it assumes you have given it a good sets of corresponding stars.
634 
635  NOTE that "refCat" and "sourceCat" are assumed to be the same length;
636  entries "refCat[i]" and "sourceCat[i]" are assumed to be correspondences.
637 
638  @param[in] origWcs the WCS to linearize in order to get the TAN part of the TAN-SIP WCS.
639  @param[in] refCat reference source catalog
640  @param[in] sourceCat source catalog
641  @param[in] bbox bounding box of image
642  """
643  sipOrder = self.config.sipOrder
644  matches = []
645  for ci, si in zip(refCat, sourceCat):
646  matches.append(afwTable.ReferenceMatch(ci, si, 0.))
647 
648  sipObject = astromSip.makeCreateWcsWithSip(matches, origWcs, sipOrder, bbox)
649  return sipObject.getNewWcs()
650 
Lightweight representation of a geometric match between two records.
Definition: fwd.h:101

◆ getSipWcsFromWcs()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.getSipWcsFromWcs (   self,
  wcs,
  bbox,
  ngrid = 20,
  linearizeAtCenter = True 
)

Get a TAN-SIP WCS, starting from an existing WCS.

It uses your WCS to compute a fake grid of corresponding "stars" in pixel and sky coords, and feeds that to the regular SIP code.

Parameters
[in]wcsinitial WCS
[in]bboxbounding box of image
[in]ngridnumber of grid points along x and y for fitting (fit at ngrid^2 points)
[in]linearizeAtCenterif True, get a linear approximation of the input WCS at the image center and use that as the TAN initialization for the TAN-SIP solution. You probably want this if your WCS has its CRPIX outside the image bounding box.

Definition at line 578 of file anetBasicAstrometry.py.

578  def getSipWcsFromWcs(self, wcs, bbox, ngrid=20, linearizeAtCenter=True):
579  """!Get a TAN-SIP WCS, starting from an existing WCS.
580 
581  It uses your WCS to compute a fake grid of corresponding "stars" in pixel and sky coords,
582  and feeds that to the regular SIP code.
583 
584  @param[in] wcs initial WCS
585  @param[in] bbox bounding box of image
586  @param[in] ngrid number of grid points along x and y for fitting (fit at ngrid^2 points)
587  @param[in] linearizeAtCenter if True, get a linear approximation of the input
588  WCS at the image center and use that as the TAN initialization for
589  the TAN-SIP solution. You probably want this if your WCS has its
590  CRPIX outside the image bounding box.
591  """
592  # Ugh, build src and ref tables
593  srcSchema = afwTable.SourceTable.makeMinimalSchema()
594  key = srcSchema.addField("centroid", type="PointD")
595  srcTable = afwTable.SourceTable.make(srcSchema)
596  srcTable.defineCentroid("centroid")
597  srcs = srcTable
598  refs = afwTable.SimpleTable.make(afwTable.SimpleTable.makeMinimalSchema())
599  cref = []
600  csrc = []
601  (W, H) = bbox.getDimensions()
602  x0, y0 = bbox.getMin()
603  for xx in np.linspace(0., W, ngrid):
604  for yy in np.linspace(0, H, ngrid):
605  src = srcs.makeRecord()
606  src.set(key.getX(), x0 + xx)
607  src.set(key.getY(), y0 + yy)
608  csrc.append(src)
609  rd = wcs.pixelToSky(xx + x0, yy + y0)
610  ref = refs.makeRecord()
611  ref.setCoord(rd)
612  cref.append(ref)
613 
614  if linearizeAtCenter:
615  # Linearize the original WCS around the image center to create a
616  # TAN WCS.
617  # Reference pixel in LSST coords
618  crpix = geom.Box2D(bbox).getCenter()
619  crval = wcs.pixelToSky(crpix)
620  crval = crval.getPosition(geom.degrees)
621  # Linearize *AT* crval to get effective CD at crval.
622  # (we use the default skyUnit of degrees as per WCS standard)
623  aff = wcs.linearizePixelToSky(crval)
624  cd = aff.getLinear().getMatrix()
625  wcs = afwImage.Wcs(crval, crpix, cd)
626 
627  return self.getSipWcsFromCorrespondences(wcs, cref, csrc, (W, H), x0=x0, y0=y0)
628 
A floating-point coordinate rectangle geometry.
Definition: Box.h:305

◆ memusage()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.memusage (   self,
  prefix = '' 
)

Definition at line 276 of file anetBasicAstrometry.py.

276  def memusage(self, prefix=''):
277  # Not logging at DEBUG: do nothing
278  if self.log.getLevel() > self.log.DEBUG:
279  return
280  from astrometry.util.ttime import get_memusage
281  mu = get_memusage()
282  ss = []
283  for key in ['VmPeak', 'VmSize', 'VmRSS', 'VmData']:
284  if key in mu:
285  ss.append(key + ': ' + ' '.join(mu[key]))
286  if 'mmaps' in mu:
287  ss.append('Mmaps: %i' % len(mu['mmaps']))
288  if 'mmaps_total' in mu:
289  ss.append('Mmaps: %i kB' % (mu['mmaps_total'] / 1024))
290  self.log.debug(prefix + 'Memory: ' + ', '.join(ss))
291 
def getLevel(loggername)

◆ plotSolution()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.plotSolution (   self,
  matches,
  wcs,
  imageSize 
)
Plot the solution, when debugging is turned on.

@param matches   The list of matches
@param wcs         The Wcs
@param imageSize   2-tuple with the image size (W,H)

Definition at line 712 of file anetBasicAstrometry.py.

712  def plotSolution(self, matches, wcs, imageSize):
713  """Plot the solution, when debugging is turned on.
714 
715  @param matches The list of matches
716  @param wcs The Wcs
717  @param imageSize 2-tuple with the image size (W,H)
718  """
719  import lsstDebug
720  display = lsstDebug.Info(__name__).display
721  if not display:
722  return
723 
724  try:
725  import matplotlib.pyplot as plt
726  except ImportError as e:
727  self.log.warn("Unable to import matplotlib: %s", e)
728  return
729 
730  fig = plt.figure(1)
731  fig.clf()
732  try:
733  fig.canvas._tkcanvas._root().lift() # == Tk's raise, but raise is a python reserved word
734  except Exception: # protect against API changes
735  pass
736 
737  num = len(matches)
738  x = np.zeros(num)
739  y = np.zeros(num)
740  dx = np.zeros(num)
741  dy = np.zeros(num)
742  for i, m in enumerate(matches):
743  x[i] = m.second.getX()
744  y[i] = m.second.getY()
745  pixel = wcs.skyToPixel(m.first.getCoord())
746  dx[i] = x[i] - pixel.getX()
747  dy[i] = y[i] - pixel.getY()
748 
749  subplots = maUtils.makeSubplots(fig, 2, 2, xgutter=0.1, ygutter=0.1, pygutter=0.04)
750 
751  def plotNext(x, y, xLabel, yLabel, xMax):
752  ax = next(subplots)
753  ax.set_autoscalex_on(False)
754  ax.set_xbound(lower=0, upper=xMax)
755  ax.scatter(x, y)
756  ax.set_xlabel(xLabel)
757  ax.set_ylabel(yLabel)
758  ax.axhline(0.0)
759 
760  plotNext(x, dx, "x", "dx", imageSize[0])
761  plotNext(x, dy, "x", "dy", imageSize[0])
762  plotNext(y, dx, "y", "dx", imageSize[1])
763  plotNext(y, dy, "y", "dy", imageSize[1])
764 
765  fig.show()
766 
767  while True:
768  try:
769  reply = input("Pausing for inspection, enter to continue... [hpQ] ").strip()
770  except EOFError:
771  reply = "n"
772 
773  reply = reply.split()
774  if reply:
775  reply = reply[0]
776  else:
777  reply = ""
778 
779  if reply in ("", "h", "p", "Q"):
780  if reply == "h":
781  print("h[elp] p[db] Q[uit]")
782  continue
783  elif reply == "p":
784  import pdb
785  pdb.set_trace()
786  elif reply == "Q":
787  sys.exit(1)
788  break
789 
bool strip
Definition: fits.cc:883

◆ useKnownWcs()

def lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.useKnownWcs (   self,
  sourceCat,
  wcs = None,
  exposure = None,
  filterName = None,
  bbox = None,
  calculateSip = None 
)

Return an InitialAstrometry object, just like determineWcs, but assuming the given input WCS is correct.

This involves searching for reference sources within the WCS area, and matching them to the given 'sourceCat'. If 'calculateSip' is set, we will try to compute a TAN-SIP distortion correction.

Parameters
[in]sourceCatlist of detected sources in this image.
[in]wcsyour known WCS, or None to get from exposure
[in]exposurethe exposure holding metadata for this image; if None then you must specify wcs, filterName and bbox
[in]filterNamestring, filter name, eg "i", or None to get from exposure`
[in]bboxbounding box of image, or None to get from exposure
[in]calculateSipcalculate SIP distortion terms for the WCS? If None then use self.config.calculateSip. To disable WCS fitting set calculateSip=False
Note
this function is also called by 'determineWcs' (via 'determineWcs2'), since the steps are all the same.

Definition at line 323 of file anetBasicAstrometry.py.

323  def useKnownWcs(self, sourceCat, wcs=None, exposure=None, filterName=None, bbox=None, calculateSip=None):
324  """!Return an InitialAstrometry object, just like determineWcs,
325  but assuming the given input WCS is correct.
326 
327  This involves searching for reference sources within the WCS
328  area, and matching them to the given 'sourceCat'. If
329  'calculateSip' is set, we will try to compute a TAN-SIP
330  distortion correction.
331 
332  @param[in] sourceCat list of detected sources in this image.
333  @param[in] wcs your known WCS, or None to get from exposure
334  @param[in] exposure the exposure holding metadata for this image;
335  if None then you must specify wcs, filterName and bbox
336  @param[in] filterName string, filter name, eg "i", or None to get from exposure`
337  @param[in] bbox bounding box of image, or None to get from exposure
338  @param[in] calculateSip calculate SIP distortion terms for the WCS? If None
339  then use self.config.calculateSip. To disable WCS fitting set calculateSip=False
340 
341  @note this function is also called by 'determineWcs' (via 'determineWcs2'), since the steps are all
342  the same.
343  """
344  # return value:
345  astrom = InitialAstrometry()
346 
347  if calculateSip is None:
348  calculateSip = self.config.calculateSip
349 
350  bbox, wcs, filterName = self._getImageParams(
351  exposure=exposure,
352  bbox=bbox,
353  wcs=wcs,
354  filterName=filterName,
355  wcsRequired=True,
356  )
357  refCat = self.refObjLoader.loadPixelBox(
358  bbox=bbox,
359  wcs=wcs,
360  filterName=filterName,
361  photoCalib=None,
362  ).refCat
363  astrom.refCat = refCat
364  catids = [src.getId() for src in refCat]
365  uids = set(catids)
366  self.log.debug('%i reference sources; %i unique IDs', len(catids), len(uids))
367  matches = self._getMatchList(sourceCat, refCat, wcs)
368  uniq = set([sm.second.getId() for sm in matches])
369  if len(matches) != len(uniq):
370  self.log.warn('The list of matched stars contains duplicate reference source IDs '
371  '(%i sources, %i unique ids)', len(matches), len(uniq))
372  if len(matches) == 0:
373  self.log.warn('No matches found between input sources and reference catalogue.')
374  return astrom
375 
376  self.log.debug('%i reference objects match input sources using input WCS', len(matches))
377  astrom.tanMatches = matches
378  astrom.tanWcs = wcs
379 
380  srcids = [s.getId() for s in sourceCat]
381  for m in matches:
382  assert(m.second.getId() in srcids)
383  assert(m.second in sourceCat)
384 
385  if calculateSip:
386  sipwcs, matches = self._calculateSipTerms(wcs, refCat, sourceCat, matches, bbox=bbox)
387  if sipwcs == wcs:
388  self.log.debug('Failed to find a SIP WCS better than the initial one.')
389  else:
390  self.log.debug('%i reference objects match input sources using SIP WCS',
391  len(matches))
392  astrom.sipWcs = sipwcs
393  astrom.sipMatches = matches
394 
395  wcs = astrom.getWcs()
396  # _getMatchList() modifies the source list RA,Dec coordinates.
397  # Here, we make them consistent with the WCS we are returning.
398  for src in sourceCat:
399  src.updateCoord(wcs)
400  astrom.matchMeta = _createMetadata(bbox, wcs, filterName)
401  return astrom
402 
daf::base::PropertySet * set
Definition: fits.cc:884

Member Data Documentation

◆ config

lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.config

Definition at line 266 of file anetBasicAstrometry.py.

◆ ConfigClass

lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.ConfigClass = ANetBasicAstrometryConfig
static

Definition at line 247 of file anetBasicAstrometry.py.

◆ refObjLoader

lsst.meas.extensions.astrometryNet.anetBasicAstrometry.ANetBasicAstrometryTask.refObjLoader

Definition at line 268 of file anetBasicAstrometry.py.


The documentation for this class was generated from the following file: