23 __all__ = [
"BoxGrid",
"makeSipIwcToPixel",
"makeSipPixelToIwc"]
32 from numpy.testing
import assert_allclose, assert_array_equal
33 from astshim.test import makeForwardPolyMap, makeTwoWayPolyMap
44 """Divide a box into nx by ny sub-boxes that tile the region
46 The sub-boxes will be of the same type as `box` and will exactly tile `box`;
47 they will also all be the same size, to the extent possible (some variation
48 is inevitable for integer boxes that cannot be evenly divided.
52 box : `lsst.geom.Box2I` or `lsst.geom.Box2D`
53 the box to subdivide; the boxes in the grid will be of the same type
54 numColRow : pair of `int`
55 number of columns and rows
59 if len(numColRow) != 2:
60 raise RuntimeError(f
"numColRow={numColRow!r}; must be a sequence of two integers")
61 self.
_numColRow = tuple(int(val)
for val
in numColRow)
68 raise RuntimeError(f
"Unknown class {type(box)} of box {box}")
72 minPoint = box.getMin()
74 dtype = np.array(minPoint).dtype
76 self.
_divList = [np.linspace(start=box.getMin()[i],
80 dtype=dtype)
for i
in range(2)]
87 """Return the box at the specified x,y index
91 indXY : pair of `ints`
92 the x,y index to return
96 subBox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
104 return self.shape[0]*self.shape[1]
107 """Return an iterator over all boxes, where column varies most quickly
115 """Information about a FrameSet
119 frameSet : `ast.FrameSet`
120 The FrameSet about which you want information
129 Index of current frame
130 isBaseSkyFrame : `bool`
131 Is the base frame an `ast.SkyFrame`?
132 isCurrSkyFrame : `bool`
133 Is the current frame an `ast.SkyFrame`?
143 """Return a list of ast.PolyMap coefficients for the specified SIP matrix
145 The returned list of coefficients for an ast.PolyMap
146 that computes the following function:
148 f(dxy) = dxy + sipPolynomial(dxy))
149 where dxy = pixelPosition - pixelOrigin
150 and sipPolynomial is a polynomial with terms `<name>n_m for x^n y^m`
151 (e.g. A2_0 is the coefficient for x^2 y^0)
155 metadata : lsst.daf.base.PropertySet
156 FITS metadata describing a WCS with the specified SIP coefficients
158 The desired SIP terms: one of A, B, AP, BP
163 A list of coefficients for an ast.PolyMap that computes
164 the specified SIP polynomial, including a term for out = in
168 This is an internal function for use by makeSipIwcToPixel
169 and makeSipPixelToIwc
171 outAxisDict = dict(A=1, B=2, AP=1, BP=2)
172 outAxis = outAxisDict.get(name)
174 raise RuntimeError(f
"{name} not a supported SIP name")
175 width = metadata.getAsInt(f
"{name}_ORDER") + 1
180 coeffs.append([1.0, outAxis, 1, 0])
182 coeffs.append([1.0, outAxis, 0, 1])
184 for xPower
in range(width):
185 for yPower
in range(width):
186 coeffName = f
"{name}_{xPower}_{yPower}"
187 if not metadata.exists(coeffName):
190 coeff = metadata.getAsDouble(coeffName)
191 coeffs.append([coeff, outAxis, xPower, yPower])
193 raise RuntimeError(f
"No {name} coefficients found")
198 """Make an IWC to pixel transform with SIP distortion from FITS-WCS metadata
200 This function is primarily intended for unit tests.
201 IWC is intermediate world coordinates, as described in the FITS papers.
205 metadata : lsst.daf.base.PropertySet
206 FITS metadata describing a WCS with inverse SIP coefficients
210 lsst.afw.geom.TransformPoint2ToPoint2
211 Transform from IWC position to pixel position (zero-based)
212 in the forward direction. The inverse direction is not defined.
217 The inverse SIP terms APn_m, BPn_m are polynomial coefficients x^n y^m
218 for computing transformed x, y respectively. If we call the resulting
219 polynomial inverseSipPolynomial, the returned transformation is:
221 pixelPosition = pixel origin + uv + inverseSipPolynomial(uv)
222 where uv = inverseCdMatrix * iwcPosition
224 crpix = (metadata.getScalar(
"CRPIX1") - 1, metadata.getScalar(
"CRPIX2") - 1)
229 coeffArr = np.array(coeffList, dtype=float)
230 sipPolyMap =
ast.PolyMap(coeffArr, 2,
"IterInverse=0")
232 iwcToPixelMap = cdMatrixMap.inverted().
then(sipPolyMap).
then(pixelRelativeToAbsoluteMap)
237 """Make a pixel to IWC transform with SIP distortion from FITS-WCS metadata
239 This function is primarily intended for unit tests.
240 IWC is intermediate world coordinates, as described in the FITS papers.
244 metadata : lsst.daf.base.PropertySet
245 FITS metadata describing a WCS with forward SIP coefficients
249 lsst.afw.geom.TransformPoint2ToPoint2
250 Transform from pixel position (zero-based) to IWC position
251 in the forward direction. The inverse direction is not defined.
256 The forward SIP terms An_m, Bn_m are polynomial coefficients x^n y^m
257 for computing transformed x, y respectively. If we call the resulting
258 polynomial sipPolynomial, the returned transformation is:
260 iwcPosition = cdMatrix * (dxy + sipPolynomial(dxy))
261 where dxy = pixelPosition - pixelOrigin
263 crpix = (metadata.getScalar(
"CRPIX1") - 1, metadata.getScalar(
"CRPIX2") - 1)
264 pixelAbsoluteToRelativeMap =
ast.ShiftMap(crpix).inverted()
268 coeffArr = np.array(coeffList, dtype=float)
269 sipPolyMap =
ast.PolyMap(coeffArr, 2,
"IterInverse=0")
270 pixelToIwcMap = pixelAbsoluteToRelativeMap.then(sipPolyMap).
then(cdMatrixMap)
275 """A FrameSet with base or current frame possibly permuted, with associated
278 Only two-axis frames will be permuted.
282 frameSet : `ast.FrameSet`
283 The FrameSet you wish to permute. A deep copy is made.
285 Permute the base frame's axes?
287 Permute the current frame's axes?
292 If you try to permute a frame that does not have 2 axes
298 frameSet : `ast.FrameSet`
299 The FrameSet that may be permuted. A local copy is made.
300 isBaseSkyFrame : `bool`
301 Is the base frame an `ast.SkyFrame`?
302 isCurrSkyFrame : `bool`
303 Is the current frame an `ast.SkyFrame`?
304 isBasePermuted : `bool`
305 Are the base frame axes permuted?
306 isCurrPermuted : `bool`
307 Are the current frame axes permuted?
309 def __init__(self, frameSet, permuteBase, permuteCurr):
317 raise RuntimeError(
"Base frame has {} axes; 2 required to permute".
format(baseNAxes))
318 self.
frameSet.current = fsInfo.baseInd
320 self.
frameSet.current = fsInfo.currInd
324 raise RuntimeError(
"Current frame has {} axes; 2 required to permute".
format(currNAxes))
332 """Base class for unit tests of Transform<X>To<Y>
334 Subclasses must call `TransformTestBaseClass.setUp(self)`
335 if they provide their own version.
337 If a package other than afw uses this class then it must
338 override the `getTestDir` method to avoid writing into
339 afw's test directory.
343 """Return a directory where temporary test files can be written
345 The default implementation returns the test directory of the `afw`
348 If this class is used by a test in a package other than `afw`
349 then the subclass must override this method.
356 Subclasses should call this method if they override setUp.
368 "Generic": (1, 2, 3, 4),
378 "SpherePoint": (1, 3, 4),
391 """Make an array of generic point data
393 The data will be suitable for spherical points
398 Number of points in the array
400 Number of axes in the point
404 np.array of floats with shape (nAxes, nPoints)
405 The values are as follows; if nAxes != 2:
406 The first point has values `[0, delta, 2*delta, ..., (nAxes-1)*delta]`
407 The Nth point has those values + N
408 if nAxes == 2 then the data is scaled so that the max value of axis 1
409 is a bit less than pi/2
413 oneAxis = np.arange(nPoints, dtype=float)
415 rawData = np.array([j * delta + oneAxis
for j
in range(nAxes)], dtype=float)
419 maxLatitude = np.max(rawData[1])
420 rawData *= math.pi * 0.4999 / maxLatitude
425 """Make one generic point
430 Number of axes in the point
432 Increment between axis values
436 A list of `nAxes` floats with values `[0, delta, ..., (nAxes-1)*delta]
438 return [i*delta
for i
in range(nAxes)]
447 Endpoint class name prefix; the full class name is name + "Endpoint"
448 nAxes : `int` or `None`, optional
449 number of axes; an int is required if `name` == "Generic";
454 subclass of `lsst.afw.geom.BaseEndpoint`
455 The constructed endpoint
460 If `name` == "Generic" and `nAxes` is None or <= 0
462 EndpointClassName = name +
"Endpoint"
463 EndpointClass = getattr(afwGeom, EndpointClassName)
464 if name ==
"Generic":
466 raise TypeError(
"nAxes must be an integer for GenericEndpoint")
467 return EndpointClass(nAxes)
468 return EndpointClass()
472 """Return the appropriate frame for the given name and nAxes
477 Endpoint class name prefix; the full class name is name + "Endpoint"
478 nAxes : `int` or `None`, optional
479 number of axes; an int is required if `name` == "Generic";
485 The constructed frame
490 If `name` == "Generic" and `nAxes` is `None` or <= 0
496 """Return a list of 0 or more frames that are not a valid match for the
502 Endpoint class name prefix; the full class name is name + "Endpoint"
506 Collection of `ast.Frame`
507 A collection of 0 or more frames
526 The FrameSet will contain 4 frames and three transforms connecting them.
527 The idenity of each frame is provided by self.frameIdentDict
529 Frame Index Mapping from this frame to the next
530 `baseFrame` 1 `ast.UnitMap(nIn)`
531 Frame(nIn) 2 `polyMap`
532 Frame(nOut) 3 `ast.UnitMap(nOut)`
536 - `nIn` = `baseFrame.nAxes`
537 - `nOut` = `currFrame.nAxes`
538 - `polyMap` = `makeTwoWayPolyMap(nIn, nOut)`
543 The FrameSet as described above
547 baseFrame : `ast.Frame`
549 currFrame : `ast.Frame`
552 nIn = baseFrame.nAxes
553 nOut = currFrame.nAxes
558 baseFrame = baseFrame.copy()
560 currFrame = currFrame.copy()
566 frameSet.addFrame(ast.FrameSet.CURRENT,
ast.UnitMap(nIn), frame2)
569 frameSet.addFrame(ast.FrameSet.CURRENT, polyMap, frame3)
570 frameSet.addFrame(ast.FrameSet.CURRENT,
ast.UnitMap(nOut), currFrame)
575 """Iterator over 0 or more frameSets with SkyFrames axes permuted
577 Only base and current SkyFrames are permuted. If neither the base nor
578 the current frame is a SkyFrame then no frames are returned.
582 iterator over `PermutedFrameSet`
586 if not (fsInfo.isBaseSkyFrame
or fsInfo.isCurrSkyFrame):
589 permuteBaseList = [
False,
True]
if fsInfo.isBaseSkyFrame
else [
False]
590 permuteCurrList = [
False,
True]
if fsInfo.isCurrSkyFrame
else [
False]
591 for permuteBase
in permuteBaseList:
592 for permuteCurr
in permuteCurrList:
597 """Make a Jacobian matrix for the equation described by
603 the dimensions of the input and output data; see makeTwoWayPolyMap
604 inPoint : `numpy.ndarray`
605 an array of size `nIn` representing the point at which the Jacobian
611 an `nOut` x `nIn` array of first derivatives
613 basePolyMapCoeff = 0.001
614 baseCoeff = 2.0 * basePolyMapCoeff
615 coeffs = np.empty((nOut, nIn))
616 for iOut
in range(nOut):
617 coeffOffset = baseCoeff * iOut
618 for iIn
in range(nIn):
619 coeffs[iOut, iIn] = baseCoeff * (iIn + 1) + coeffOffset
620 coeffs[iOut, iIn] *= inPoint[iIn]
621 assert coeffs.ndim == 2
623 assert coeffs.shape == (nOut, nIn)
627 """Check applyForward and applyInverse for a transform
631 transform : `lsst.afw.geom.Transform`
632 The transform to check
633 mapping : `ast.Mapping`
634 The mapping the transform should use. This mapping
635 must contain valid forward or inverse transformations,
636 but they need not match if both present. Hence the
637 mappings returned by make*PolyMap are acceptable.
639 Error message suffix describing test parameters
641 fromEndpoint = transform.fromEndpoint
642 toEndpoint = transform.toEndpoint
643 mappingFromTransform = transform.getMapping()
647 self.assertEqual(nIn, fromEndpoint.nAxes, msg=msg)
648 self.assertEqual(nOut, toEndpoint.nAxes, msg=msg)
652 inPoint = fromEndpoint.pointFromData(rawInPoint)
657 inArray = fromEndpoint.arrayFromData(rawInArray)
659 if mapping.hasForward:
660 self.assertTrue(transform.hasForward)
661 outPoint = transform.applyForward(inPoint)
662 rawOutPoint = toEndpoint.dataFromPoint(outPoint)
663 assert_allclose(rawOutPoint, mapping.applyForward(rawInPoint), err_msg=msg)
664 assert_allclose(rawOutPoint, mappingFromTransform.applyForward(rawInPoint), err_msg=msg)
666 outArray = transform.applyForward(inArray)
667 rawOutArray = toEndpoint.dataFromArray(outArray)
668 self.assertFloatsAlmostEqual(rawOutArray, mapping.applyForward(rawInArray), msg=msg)
669 self.assertFloatsAlmostEqual(rawOutArray, mappingFromTransform.applyForward(rawInArray), msg=msg)
673 outPoint = toEndpoint.pointFromData(rawOutPoint)
675 outArray = toEndpoint.arrayFromData(rawOutArray)
677 self.assertFalse(transform.hasForward)
679 if mapping.hasInverse:
680 self.assertTrue(transform.hasInverse)
684 inversePoint = transform.applyInverse(outPoint)
685 rawInversePoint = fromEndpoint.dataFromPoint(inversePoint)
686 assert_allclose(rawInversePoint, mapping.applyInverse(rawOutPoint), err_msg=msg)
687 assert_allclose(rawInversePoint, mappingFromTransform.applyInverse(rawOutPoint), err_msg=msg)
692 inverseArray = transform.applyInverse(outArray)
693 rawInverseArray = fromEndpoint.dataFromArray(inverseArray)
694 self.assertFloatsAlmostEqual(rawInverseArray, mapping.applyInverse(rawOutArray), msg=msg)
695 self.assertFloatsAlmostEqual(rawInverseArray, mappingFromTransform.applyInverse(rawOutArray),
698 self.assertFalse(transform.hasInverse)
701 """Check that two Transforms are each others' inverses.
705 forward : `lsst.afw.geom.Transform`
706 the reference Transform to test
707 inverse : `lsst.afw.geom.Transform`
708 the transform that should be the inverse of `forward`
710 error message suffix describing test parameters
712 fromEndpoint = forward.fromEndpoint
713 toEndpoint = forward.toEndpoint
714 forwardMapping = forward.getMapping()
715 inverseMapping = inverse.getMapping()
718 self.assertEqual(forward.fromEndpoint,
719 inverse.toEndpoint, msg=msg)
720 self.assertEqual(forward.toEndpoint,
721 inverse.fromEndpoint, msg=msg)
722 self.assertEqual(forward.hasForward, inverse.hasInverse, msg=msg)
723 self.assertEqual(forward.hasInverse, inverse.hasForward, msg=msg)
729 inPoint = fromEndpoint.pointFromData(rawInPoint)
731 outPoint = toEndpoint.pointFromData(rawOutPoint)
736 inArray = fromEndpoint.arrayFromData(rawInArray)
738 outArray = toEndpoint.arrayFromData(rawOutArray)
740 if forward.hasForward:
741 self.assertEqual(forward.applyForward(inPoint),
742 inverse.applyInverse(inPoint), msg=msg)
743 self.assertEqual(forwardMapping.applyForward(rawInPoint),
744 inverseMapping.applyInverse(rawInPoint), msg=msg)
746 assert_array_equal(forward.applyForward(inArray),
747 inverse.applyInverse(inArray),
749 assert_array_equal(forwardMapping.applyForward(rawInArray),
750 inverseMapping.applyInverse(rawInArray),
753 if forward.hasInverse:
754 self.assertEqual(forward.applyInverse(outPoint),
755 inverse.applyForward(outPoint), msg=msg)
756 self.assertEqual(forwardMapping.applyInverse(rawOutPoint),
757 inverseMapping.applyForward(rawOutPoint), msg=msg)
758 assert_array_equal(forward.applyInverse(outArray),
759 inverse.applyForward(outArray),
761 assert_array_equal(forwardMapping.applyInverse(rawOutArray),
762 inverseMapping.applyForward(rawOutArray),
766 """Check Transform_<fromName>_<toName> using the Mapping constructor
770 fromName, toName : `str`
771 Endpoint name prefix for "from" and "to" endpoints, respectively,
772 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
773 fromAxes, toAxes : `int`
774 number of axes in fromFrame and toFrame, respectively
776 transformClassName =
"Transform{}To{}".
format(fromName, toName)
777 TransformClass = getattr(afwGeom, transformClassName)
778 baseMsg =
"TransformClass={}".
format(TransformClass.__name__)
781 for nIn, nOut
in itertools.product(self.
goodNAxes[fromName],
783 msg =
"{}, nIn={}, nOut={}".
format(baseMsg, nIn, nOut)
788 desStr =
"{}[{}->{}]".
format(transformClassName, nIn, nOut)
789 self.assertEqual(
"{}".
format(transform), desStr)
790 self.assertEqual(repr(transform),
"lsst.afw.geom." + desStr)
805 for nIn, badNOut
in itertools.product(self.
goodNAxes[fromName],
808 msg =
"{}, nIn={}, badNOut={}".
format(baseMsg, nIn, badNOut)
809 with self.assertRaises(InvalidParameterError, msg=msg):
813 for badNIn, nOut
in itertools.product(self.
badNAxes[fromName],
816 msg =
"{}, badNIn={}, nOut={}".
format(baseMsg, nIn, nOut)
817 with self.assertRaises(InvalidParameterError, msg=msg):
821 """Check Transform_<fromName>_<toName> using the FrameSet constructor
825 fromName, toName : `str`
826 Endpoint name prefix for "from" and "to" endpoints, respectively,
827 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
829 transformClassName =
"Transform{}To{}".
format(fromName, toName)
830 TransformClass = getattr(afwGeom, transformClassName)
831 baseMsg =
"TransformClass={}".
format(TransformClass.__name__)
832 for nIn, nOut
in itertools.product(self.
goodNAxes[fromName],
834 msg =
"{}, nIn={}, nOut={}".
format(baseMsg, nIn, nOut)
839 self.assertEqual(frameSet.nFrame, 4)
843 badFrameSet = self.
makeFrameSet(badBaseFrame, currFrame)
844 with self.assertRaises(InvalidParameterError):
847 reallyBadFrameSet = self.
makeFrameSet(badBaseFrame, badCurrFrame)
848 with self.assertRaises(InvalidParameterError):
851 badFrameSet = self.
makeFrameSet(baseFrame, badCurrFrame)
852 with self.assertRaises(InvalidParameterError):
857 desStr =
"{}[{}->{}]".
format(transformClassName, nIn, nOut)
858 self.assertEqual(
"{}".
format(transform), desStr)
859 self.assertEqual(repr(transform),
"lsst.afw.geom." + desStr)
863 mappingFromTransform = transform.getMapping()
865 self.assertEqual(
type(transform),
type(transformCopy))
866 self.assertEqual(transform.getMapping(), mappingFromTransform)
878 if permutedFS.isBaseSkyFrame:
879 baseFrame = permutedFS.frameSet.getFrame(ast.FrameSet.BASE)
881 desBaseLonAxis = 2
if permutedFS.isBasePermuted
else 1
882 self.assertEqual(baseFrame.lonAxis, desBaseLonAxis)
883 if permutedFS.isCurrSkyFrame:
884 currFrame = permutedFS.frameSet.getFrame(ast.FrameSet.CURRENT)
886 desCurrLonAxis = 2
if permutedFS.isCurrPermuted
else 1
887 self.assertEqual(currFrame.lonAxis, desCurrLonAxis)
893 """Test Transform<fromName>To<toName>.inverted
897 fromName, toName : `str`
898 Endpoint name prefix for "from" and "to" endpoints, respectively,
899 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
901 transformClassName =
"Transform{}To{}".
format(fromName, toName)
902 TransformClass = getattr(afwGeom, transformClassName)
903 baseMsg =
"TransformClass={}".
format(TransformClass.__name__)
904 for nIn, nOut
in itertools.product(self.
goodNAxes[fromName],
906 msg =
"{}, nIn={}, nOut={}".
format(baseMsg, nIn, nOut)
910 "{}, Map={}".
format(msg,
"TwoWay"))
914 "{}, Map={}".
format(msg,
"Forward"))
918 "{}, Map={}".
format(msg,
"Inverse"))
921 """Test Transform<fromName>To<toName>.inverted for a specific
924 Also check that inverted() and getInverted() return the same
929 TransformClass : `type`
930 The class of transform to test, such as TransformPoint2ToPoint2
931 mapping : `ast.Mapping`
932 The mapping to use for the transform
937 inverse = transform.inverted()
938 inverseInverse = inverse.inverted()
945 """Test Transform<fromName>To<toName>.getJacobian
949 fromName, toName : `str`
950 Endpoint name prefix for "from" and "to" endpoints, respectively,
951 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
953 transformClassName =
"Transform{}To{}".
format(fromName, toName)
954 TransformClass = getattr(afwGeom, transformClassName)
955 baseMsg =
"TransformClass={}".
format(TransformClass.__name__)
956 for nIn, nOut
in itertools.product(self.
goodNAxes[fromName],
958 msg =
"{}, nIn={}, nOut={}".
format(baseMsg, nIn, nOut)
961 fromEndpoint = transform.fromEndpoint
965 inPoint = fromEndpoint.pointFromData(rawInPoint)
966 jacobian = transform.getJacobian(inPoint)
967 assert_allclose(jacobian, self.
makeJacobian(nIn, nOut, rawInPoint),
971 inPoint = fromEndpoint.pointFromData(rawInPoint)
972 jacobian = transform.getJacobian(inPoint)
973 assert_allclose(jacobian, self.
makeJacobian(nIn, nOut, rawInPoint),
977 """Test Transform<fromName>To<midName>.then(Transform<midName>To<toName>)
982 the prefix of the starting endpoint (e.g., "Point2" for a
983 Point2Endpoint) for the final, concatenated Transform
985 the prefix for the shared endpoint where two Transforms will be
988 the prefix of the ending endpoint for the final, concatenated
991 TransformClass1 = getattr(afwGeom,
992 "Transform{}To{}".
format(fromName, midName))
993 TransformClass2 = getattr(afwGeom,
994 "Transform{}To{}".
format(midName, toName))
995 baseMsg =
"{}.then({})".
format(TransformClass1.__name__,
996 TransformClass2.__name__)
997 for nIn, nMid, nOut
in itertools.product(self.
goodNAxes[fromName],
1000 msg =
"{}, nIn={}, nMid={}, nOut={}".
format(
1001 baseMsg, nIn, nMid, nOut)
1003 transform1 = TransformClass1(polyMap1)
1005 transform2 = TransformClass2(polyMap2)
1006 transform = transform1.then(transform2)
1008 fromEndpoint = transform1.fromEndpoint
1009 toEndpoint = transform2.toEndpoint
1012 outPointMerged = transform.applyForward(inPoint)
1013 outPointSeparate = transform2.applyForward(
1014 transform1.applyForward(inPoint))
1015 assert_allclose(toEndpoint.dataFromPoint(outPointMerged),
1016 toEndpoint.dataFromPoint(outPointSeparate),
1020 inPointMerged = transform.applyInverse(outPoint)
1021 inPointSeparate = transform1.applyInverse(
1022 transform2.applyInverse(outPoint))
1024 fromEndpoint.dataFromPoint(inPointMerged),
1025 fromEndpoint.dataFromPoint(inPointSeparate),
1029 if midName ==
"Generic":
1033 transform1 = TransformClass1(polyMap)
1035 transform2 = TransformClass2(polyMap)
1036 with self.assertRaises(InvalidParameterError):
1037 transform = transform1.then(transform2)
1040 if fromName != midName:
1043 joinNAxes =
set(self.
goodNAxes[fromName]).intersection(
1046 for nIn, nMid, nOut
in itertools.product(self.
goodNAxes[fromName],
1050 transform1 = TransformClass1(polyMap)
1052 transform2 = TransformClass1(polyMap)
1053 with self.assertRaises(InvalidParameterError):
1054 transform = transform1.then(transform2)
1057 """Assert that two transforms are equal"""
1058 self.assertEqual(
type(transform1),
type(transform2))
1059 self.assertEqual(transform1.fromEndpoint, transform2.fromEndpoint)
1060 self.assertEqual(transform1.toEndpoint, transform2.toEndpoint)
1061 self.assertEqual(transform1.getMapping(), transform2.getMapping())
1063 fromEndpoint = transform1.fromEndpoint
1064 toEndpoint = transform1.toEndpoint
1065 mapping = transform1.getMapping()
1069 if mapping.hasForward:
1072 inArray = fromEndpoint.arrayFromData(rawInArray)
1073 outArray = transform1.applyForward(inArray)
1074 outData = toEndpoint.dataFromArray(outArray)
1075 outArrayRoundTrip = transform2.applyForward(inArray)
1076 outDataRoundTrip = toEndpoint.dataFromArray(outArrayRoundTrip)
1077 assert_allclose(outData, outDataRoundTrip)
1079 if mapping.hasInverse:
1082 outArray = toEndpoint.arrayFromData(rawOutArray)
1083 inArray = transform1.applyInverse(outArray)
1084 inData = fromEndpoint.dataFromArray(inArray)
1085 inArrayRoundTrip = transform2.applyInverse(outArray)
1086 inDataRoundTrip = fromEndpoint.dataFromArray(inArrayRoundTrip)
1087 assert_allclose(inData, inDataRoundTrip)
1090 """Check persistence of a transform
1092 className =
type(transform).__name__
1095 transformStr = transform.writeString()
1096 serialVersion, serialClassName, serialRest = transformStr.split(
" ", 2)
1097 self.assertEqual(int(serialVersion), 1)
1098 self.assertEqual(serialClassName, className)
1099 badStr1 =
" ".join([
"2", serialClassName, serialRest])
1101 transform.readString(badStr1)
1102 badClassName =
"x" + serialClassName
1103 badStr2 =
" ".join([
"1", badClassName, serialRest])
1105 transform.readString(badStr2)
1106 transformFromStr1 = transform.readString(transformStr)
1110 transformFromStr2 = afwGeom.transformFromString(transformStr)
1118 transform.writeFits(filename)