LSST Applications g0265f82a02+0e5473021a,g02d81e74bb+f5613e8b4f,g1470d8bcf6+190ad2ba91,g14a832a312+311607e4ab,g2079a07aa2+86d27d4dc4,g2305ad1205+a8e3196225,g295015adf3+b67ee847e5,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g3ddfee87b4+a761f810f3,g487adcacf7+17c8fdbcbd,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+65b5bd823e,g5a732f18d5+53520f316c,g64a986408d+f5613e8b4f,g6c1bc301e9+51106c2951,g858d7b2824+f5613e8b4f,g8a8a8dda67+585e252eca,g99cad8db69+6729933424,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+ef4e3a5875,gb0e22166c9+60f28cb32d,gb6a65358fc+0e5473021a,gba4ed39666+c2a2e4ac27,gbb8dafda3b+e9bba80f27,gc120e1dc64+eee469a5e5,gc28159a63d+0e5473021a,gcf0d15dbbd+a761f810f3,gdaeeff99f8+f9a426f77a,ge6526c86ff+d4c1d4bfef,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gf1cff7945b+f5613e8b4f,w.2024.16
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Public Attributes | List of all members
lsst.afw.geom.testUtils.TransformTestBaseClass Class Reference
Inheritance diagram for lsst.afw.geom.testUtils.TransformTestBaseClass:

Public Member Functions

 getTestDir (self)
 
 setUp (self)
 
 makeGoodFrame (cls, name, nAxes=None)
 
 makeFrameSet (self, baseFrame, currFrame)
 
 checkTransformation (self, transform, mapping, msg="")
 
 checkInverseTransformation (self, forward, inverse, msg="")
 
 checkTransformFromMapping (self, fromName, toName)
 
 checkTransformFromFrameSet (self, fromName, toName)
 
 checkInverted (self, fromName, toName)
 
 checkInverseMapping (self, TransformClass, mapping, msg)
 
 checkGetJacobian (self, fromName, toName)
 
 checkThen (self, fromName, midName, toName)
 
 assertTransformsEqual (self, transform1, transform2)
 
 checkPersistence (self, transform)
 

Static Public Member Functions

 makeRawArrayData (nPoints, nAxes, delta=0.123)
 
 makeRawPointData (nAxes, delta=0.123)
 
 makeEndpoint (name, nAxes=None)
 
 makeBadFrames (name)
 
 permuteFrameSetIter (frameSet)
 
 makeJacobian (nIn, nOut, inPoint)
 

Public Attributes

 longMessage
 
 endpointPrefixes
 
 goodNAxes
 
 badNAxes
 
 frameIdentDict
 

Detailed Description

Base class for unit tests of Transform<X>To<Y>

Subclasses must call `TransformTestBaseClass.setUp(self)`
if they provide their own version.

If a package other than afw uses this class then it must
override the `getTestDir` method to avoid writing into
afw's test directory.

Definition at line 330 of file testUtils.py.

Member Function Documentation

◆ assertTransformsEqual()

lsst.afw.geom.testUtils.TransformTestBaseClass.assertTransformsEqual ( self,
transform1,
transform2 )
Assert that two transforms are equal

Definition at line 1055 of file testUtils.py.

1055 def assertTransformsEqual(self, transform1, transform2):
1056 """Assert that two transforms are equal"""
1057 self.assertEqual(type(transform1), type(transform2))
1058 self.assertEqual(transform1.fromEndpoint, transform2.fromEndpoint)
1059 self.assertEqual(transform1.toEndpoint, transform2.toEndpoint)
1060 self.assertEqual(transform1.getMapping(), transform2.getMapping())
1061
1062 fromEndpoint = transform1.fromEndpoint
1063 toEndpoint = transform1.toEndpoint
1064 mapping = transform1.getMapping()
1065 nIn = mapping.nIn
1066 nOut = mapping.nOut
1067
1068 if mapping.hasForward:
1069 nPoints = 7 # arbitrary
1070 rawInArray = self.makeRawArrayData(nPoints, nIn)
1071 inArray = fromEndpoint.arrayFromData(rawInArray)
1072 outArray = transform1.applyForward(inArray)
1073 outData = toEndpoint.dataFromArray(outArray)
1074 outArrayRoundTrip = transform2.applyForward(inArray)
1075 outDataRoundTrip = toEndpoint.dataFromArray(outArrayRoundTrip)
1076 assert_allclose(outData, outDataRoundTrip)
1077
1078 if mapping.hasInverse:
1079 nPoints = 7 # arbitrary
1080 rawOutArray = self.makeRawArrayData(nPoints, nOut)
1081 outArray = toEndpoint.arrayFromData(rawOutArray)
1082 inArray = transform1.applyInverse(outArray)
1083 inData = fromEndpoint.dataFromArray(inArray)
1084 inArrayRoundTrip = transform2.applyInverse(outArray)
1085 inDataRoundTrip = fromEndpoint.dataFromArray(inArrayRoundTrip)
1086 assert_allclose(inData, inDataRoundTrip)
1087

◆ checkGetJacobian()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkGetJacobian ( self,
fromName,
toName )
Test Transform<fromName>To<toName>.getJacobian

Parameters
----------
fromName, toName : `str`
    Endpoint name prefix for "from" and "to" endpoints, respectively,
    e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`

Definition at line 943 of file testUtils.py.

943 def checkGetJacobian(self, fromName, toName):
944 """Test Transform<fromName>To<toName>.getJacobian
945
946 Parameters
947 ----------
948 fromName, toName : `str`
949 Endpoint name prefix for "from" and "to" endpoints, respectively,
950 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
951 """
952 transformClassName = "Transform{}To{}".format(fromName, toName)
953 TransformClass = getattr(afwGeom, transformClassName)
954 baseMsg = "TransformClass={}".format(TransformClass.__name__)
955 for nIn, nOut in itertools.product(self.goodNAxes[fromName],
956 self.goodNAxes[toName]):
957 msg = "{}, nIn={}, nOut={}".format(baseMsg, nIn, nOut)
958 polyMap = makeForwardPolyMap(nIn, nOut)
959 transform = TransformClass(polyMap)
960 fromEndpoint = transform.fromEndpoint
961
962 # Test multiple points to ensure correct functional form
963 rawInPoint = self.makeRawPointData(nIn)
964 inPoint = fromEndpoint.pointFromData(rawInPoint)
965 jacobian = transform.getJacobian(inPoint)
966 assert_allclose(jacobian, self.makeJacobian(nIn, nOut, rawInPoint),
967 err_msg=msg)
968
969 rawInPoint = self.makeRawPointData(nIn, 0.111)
970 inPoint = fromEndpoint.pointFromData(rawInPoint)
971 jacobian = transform.getJacobian(inPoint)
972 assert_allclose(jacobian, self.makeJacobian(nIn, nOut, rawInPoint),
973 err_msg=msg)
974

◆ checkInverseMapping()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkInverseMapping ( self,
TransformClass,
mapping,
msg )
Test Transform<fromName>To<toName>.inverted for a specific
mapping.

Also check that inverted() and getInverted() return the same
transform.

Parameters
----------
TransformClass : `type`
    The class of transform to test, such as TransformPoint2ToPoint2
mapping : `ast.Mapping`
    The mapping to use for the transform
msg : `str`
    Error message suffix

Definition at line 919 of file testUtils.py.

919 def checkInverseMapping(self, TransformClass, mapping, msg):
920 """Test Transform<fromName>To<toName>.inverted for a specific
921 mapping.
922
923 Also check that inverted() and getInverted() return the same
924 transform.
925
926 Parameters
927 ----------
928 TransformClass : `type`
929 The class of transform to test, such as TransformPoint2ToPoint2
930 mapping : `ast.Mapping`
931 The mapping to use for the transform
932 msg : `str`
933 Error message suffix
934 """
935 transform = TransformClass(mapping)
936 inverse = transform.inverted()
937 inverseInverse = inverse.inverted()
938
939 self.checkInverseTransformation(transform, inverse, msg=msg)
940 self.checkInverseTransformation(inverse, inverseInverse, msg=msg)
941 self.checkTransformation(inverseInverse, mapping, msg=msg)
942

◆ checkInverseTransformation()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkInverseTransformation ( self,
forward,
inverse,
msg = "" )
Check that two Transforms are each others' inverses.

Parameters
----------
forward : `lsst.afw.geom.Transform`
    the reference Transform to test
inverse : `lsst.afw.geom.Transform`
    the transform that should be the inverse of `forward`
msg : `str`
    error message suffix describing test parameters

Definition at line 699 of file testUtils.py.

699 def checkInverseTransformation(self, forward, inverse, msg=""):
700 """Check that two Transforms are each others' inverses.
701
702 Parameters
703 ----------
704 forward : `lsst.afw.geom.Transform`
705 the reference Transform to test
706 inverse : `lsst.afw.geom.Transform`
707 the transform that should be the inverse of `forward`
708 msg : `str`
709 error message suffix describing test parameters
710 """
711 fromEndpoint = forward.fromEndpoint
712 toEndpoint = forward.toEndpoint
713 forwardMapping = forward.getMapping()
714 inverseMapping = inverse.getMapping()
715
716 # properties
717 self.assertEqual(forward.fromEndpoint,
718 inverse.toEndpoint, msg=msg)
719 self.assertEqual(forward.toEndpoint,
720 inverse.fromEndpoint, msg=msg)
721 self.assertEqual(forward.hasForward, inverse.hasInverse, msg=msg)
722 self.assertEqual(forward.hasInverse, inverse.hasForward, msg=msg)
723
724 # transformations of one point
725 # we don't care about whether the transformation itself is correct
726 # (see checkTransformation), so inPoint/outPoint need not be related
727 rawInPoint = self.makeRawPointData(fromEndpoint.nAxes)
728 inPoint = fromEndpoint.pointFromData(rawInPoint)
729 rawOutPoint = self.makeRawPointData(toEndpoint.nAxes)
730 outPoint = toEndpoint.pointFromData(rawOutPoint)
731
732 # transformations of arrays of points
733 nPoints = 7 # arbitrary
734 rawInArray = self.makeRawArrayData(nPoints, fromEndpoint.nAxes)
735 inArray = fromEndpoint.arrayFromData(rawInArray)
736 rawOutArray = self.makeRawArrayData(nPoints, toEndpoint.nAxes)
737 outArray = toEndpoint.arrayFromData(rawOutArray)
738
739 if forward.hasForward:
740 self.assertEqual(forward.applyForward(inPoint),
741 inverse.applyInverse(inPoint), msg=msg)
742 self.assertEqual(forwardMapping.applyForward(rawInPoint),
743 inverseMapping.applyInverse(rawInPoint), msg=msg)
744 # Assertions must work with both lists and numpy arrays
745 assert_array_equal(forward.applyForward(inArray),
746 inverse.applyInverse(inArray),
747 err_msg=msg)
748 assert_array_equal(forwardMapping.applyForward(rawInArray),
749 inverseMapping.applyInverse(rawInArray),
750 err_msg=msg)
751
752 if forward.hasInverse:
753 self.assertEqual(forward.applyInverse(outPoint),
754 inverse.applyForward(outPoint), msg=msg)
755 self.assertEqual(forwardMapping.applyInverse(rawOutPoint),
756 inverseMapping.applyForward(rawOutPoint), msg=msg)
757 assert_array_equal(forward.applyInverse(outArray),
758 inverse.applyForward(outArray),
759 err_msg=msg)
760 assert_array_equal(forwardMapping.applyInverse(rawOutArray),
761 inverseMapping.applyForward(rawOutArray),
762 err_msg=msg)
763

◆ checkInverted()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkInverted ( self,
fromName,
toName )
Test Transform<fromName>To<toName>.inverted

Parameters
----------
fromName, toName : `str`
    Endpoint name prefix for "from" and "to" endpoints, respectively,
    e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`

Definition at line 891 of file testUtils.py.

891 def checkInverted(self, fromName, toName):
892 """Test Transform<fromName>To<toName>.inverted
893
894 Parameters
895 ----------
896 fromName, toName : `str`
897 Endpoint name prefix for "from" and "to" endpoints, respectively,
898 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
899 """
900 transformClassName = "Transform{}To{}".format(fromName, toName)
901 TransformClass = getattr(afwGeom, transformClassName)
902 baseMsg = "TransformClass={}".format(TransformClass.__name__)
903 for nIn, nOut in itertools.product(self.goodNAxes[fromName],
904 self.goodNAxes[toName]):
905 msg = "{}, nIn={}, nOut={}".format(baseMsg, nIn, nOut)
906 self.checkInverseMapping(
907 TransformClass,
908 makeTwoWayPolyMap(nIn, nOut),
909 "{}, Map={}".format(msg, "TwoWay"))
910 self.checkInverseMapping(
911 TransformClass,
912 makeForwardPolyMap(nIn, nOut),
913 "{}, Map={}".format(msg, "Forward"))
914 self.checkInverseMapping(
915 TransformClass,
916 makeForwardPolyMap(nOut, nIn).inverted(),
917 "{}, Map={}".format(msg, "Inverse"))
918

◆ checkPersistence()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkPersistence ( self,
transform )
Check persistence of a transform

Definition at line 1088 of file testUtils.py.

1088 def checkPersistence(self, transform):
1089 """Check persistence of a transform
1090 """
1091 className = type(transform).__name__
1092
1093 # check writeString and readString
1094 transformStr = transform.writeString()
1095 serialVersion, serialClassName, serialRest = transformStr.split(" ", 2)
1096 self.assertEqual(int(serialVersion), 1)
1097 self.assertEqual(serialClassName, className)
1098 badStr1 = " ".join(["2", serialClassName, serialRest])
1099 with self.assertRaises(lsst.pex.exceptions.InvalidParameterError):
1100 transform.readString(badStr1)
1101 badClassName = "x" + serialClassName
1102 badStr2 = " ".join(["1", badClassName, serialRest])
1103 with self.assertRaises(lsst.pex.exceptions.InvalidParameterError):
1104 transform.readString(badStr2)
1105 transformFromStr1 = transform.readString(transformStr)
1106 self.assertTransformsEqual(transform, transformFromStr1)
1107
1108 # check transformFromString
1109 transformFromStr2 = afwGeom.transformFromString(transformStr)
1110 self.assertTransformsEqual(transform, transformFromStr2)
1111
1112 # Check pickling
1113 self.assertTransformsEqual(transform, pickle.loads(pickle.dumps(transform)))
1114
1115 # Check afw::table::io persistence round-trip
1116 with lsst.utils.tests.getTempFilePath(".fits") as filename:
1117 transform.writeFits(filename)
1118 self.assertTransformsEqual(transform, type(transform).readFits(filename))
Reports invalid arguments.
Definition Runtime.h:66

◆ checkThen()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkThen ( self,
fromName,
midName,
toName )
Test Transform<fromName>To<midName>.then(Transform<midName>To<toName>)

Parameters
----------
fromName : `str`
    the prefix of the starting endpoint (e.g., "Point2" for a
    Point2Endpoint) for the final, concatenated Transform
midName : `str`
    the prefix for the shared endpoint where two Transforms will be
    concatenated
toName : `str`
    the prefix of the ending endpoint for the final, concatenated
    Transform

Definition at line 975 of file testUtils.py.

975 def checkThen(self, fromName, midName, toName):
976 """Test Transform<fromName>To<midName>.then(Transform<midName>To<toName>)
977
978 Parameters
979 ----------
980 fromName : `str`
981 the prefix of the starting endpoint (e.g., "Point2" for a
982 Point2Endpoint) for the final, concatenated Transform
983 midName : `str`
984 the prefix for the shared endpoint where two Transforms will be
985 concatenated
986 toName : `str`
987 the prefix of the ending endpoint for the final, concatenated
988 Transform
989 """
990 TransformClass1 = getattr(afwGeom,
991 "Transform{}To{}".format(fromName, midName))
992 TransformClass2 = getattr(afwGeom,
993 "Transform{}To{}".format(midName, toName))
994 baseMsg = "{}.then({})".format(TransformClass1.__name__,
995 TransformClass2.__name__)
996 for nIn, nMid, nOut in itertools.product(self.goodNAxes[fromName],
997 self.goodNAxes[midName],
998 self.goodNAxes[toName]):
999 msg = "{}, nIn={}, nMid={}, nOut={}".format(
1000 baseMsg, nIn, nMid, nOut)
1001 polyMap1 = makeTwoWayPolyMap(nIn, nMid)
1002 transform1 = TransformClass1(polyMap1)
1003 polyMap2 = makeTwoWayPolyMap(nMid, nOut)
1004 transform2 = TransformClass2(polyMap2)
1005 transform = transform1.then(transform2)
1006
1007 fromEndpoint = transform1.fromEndpoint
1008 toEndpoint = transform2.toEndpoint
1009
1010 inPoint = fromEndpoint.pointFromData(self.makeRawPointData(nIn))
1011 outPointMerged = transform.applyForward(inPoint)
1012 outPointSeparate = transform2.applyForward(
1013 transform1.applyForward(inPoint))
1014 assert_allclose(toEndpoint.dataFromPoint(outPointMerged),
1015 toEndpoint.dataFromPoint(outPointSeparate),
1016 err_msg=msg)
1017
1018 outPoint = toEndpoint.pointFromData(self.makeRawPointData(nOut))
1019 inPointMerged = transform.applyInverse(outPoint)
1020 inPointSeparate = transform1.applyInverse(
1021 transform2.applyInverse(outPoint))
1022 assert_allclose(
1023 fromEndpoint.dataFromPoint(inPointMerged),
1024 fromEndpoint.dataFromPoint(inPointSeparate),
1025 err_msg=msg)
1026
1027 # Mismatched number of axes should fail
1028 if midName == "Generic":
1029 nIn = self.goodNAxes[fromName][0]
1030 nOut = self.goodNAxes[toName][0]
1031 polyMap = makeTwoWayPolyMap(nIn, 3)
1032 transform1 = TransformClass1(polyMap)
1033 polyMap = makeTwoWayPolyMap(2, nOut)
1034 transform2 = TransformClass2(polyMap)
1035 with self.assertRaises(InvalidParameterError):
1036 transform = transform1.then(transform2)
1037
1038 # Mismatched types of endpoints should fail
1039 if fromName != midName:
1040 # Use TransformClass1 for both args to keep test logic simple
1041 outName = midName
1042 joinNAxes = set(self.goodNAxes[fromName]).intersection(
1043 self.goodNAxes[outName])
1044
1045 for nIn, nMid, nOut in itertools.product(self.goodNAxes[fromName],
1046 joinNAxes,
1047 self.goodNAxes[outName]):
1048 polyMap = makeTwoWayPolyMap(nIn, nMid)
1049 transform1 = TransformClass1(polyMap)
1050 polyMap = makeTwoWayPolyMap(nMid, nOut)
1051 transform2 = TransformClass1(polyMap)
1052 with self.assertRaises(InvalidParameterError):
1053 transform = transform1.then(transform2)
1054
daf::base::PropertySet * set
Definition fits.cc:931

◆ checkTransformation()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkTransformation ( self,
transform,
mapping,
msg = "" )
Check applyForward and applyInverse for a transform

Parameters
----------
transform : `lsst.afw.geom.Transform`
    The transform to check
mapping : `ast.Mapping`
    The mapping the transform should use. This mapping
    must contain valid forward or inverse transformations,
    but they need not match if both present. Hence the
    mappings returned by make*PolyMap are acceptable.
msg : `str`
    Error message suffix describing test parameters

Definition at line 625 of file testUtils.py.

625 def checkTransformation(self, transform, mapping, msg=""):
626 """Check applyForward and applyInverse for a transform
627
628 Parameters
629 ----------
630 transform : `lsst.afw.geom.Transform`
631 The transform to check
632 mapping : `ast.Mapping`
633 The mapping the transform should use. This mapping
634 must contain valid forward or inverse transformations,
635 but they need not match if both present. Hence the
636 mappings returned by make*PolyMap are acceptable.
637 msg : `str`
638 Error message suffix describing test parameters
639 """
640 fromEndpoint = transform.fromEndpoint
641 toEndpoint = transform.toEndpoint
642 mappingFromTransform = transform.getMapping()
643
644 nIn = mapping.nIn
645 nOut = mapping.nOut
646 self.assertEqual(nIn, fromEndpoint.nAxes, msg=msg)
647 self.assertEqual(nOut, toEndpoint.nAxes, msg=msg)
648
649 # forward transformation of one point
650 rawInPoint = self.makeRawPointData(nIn)
651 inPoint = fromEndpoint.pointFromData(rawInPoint)
652
653 # forward transformation of an array of points
654 nPoints = 7 # arbitrary
655 rawInArray = self.makeRawArrayData(nPoints, nIn)
656 inArray = fromEndpoint.arrayFromData(rawInArray)
657
658 if mapping.hasForward:
659 self.assertTrue(transform.hasForward)
660 outPoint = transform.applyForward(inPoint)
661 rawOutPoint = toEndpoint.dataFromPoint(outPoint)
662 assert_allclose(rawOutPoint, mapping.applyForward(rawInPoint), err_msg=msg)
663 assert_allclose(rawOutPoint, mappingFromTransform.applyForward(rawInPoint), err_msg=msg)
664
665 outArray = transform.applyForward(inArray)
666 rawOutArray = toEndpoint.dataFromArray(outArray)
667 self.assertFloatsAlmostEqual(rawOutArray, mapping.applyForward(rawInArray), msg=msg)
668 self.assertFloatsAlmostEqual(rawOutArray, mappingFromTransform.applyForward(rawInArray), msg=msg)
669 else:
670 # Need outPoint, but don't need it to be consistent with inPoint
671 rawOutPoint = self.makeRawPointData(nOut)
672 outPoint = toEndpoint.pointFromData(rawOutPoint)
673 rawOutArray = self.makeRawArrayData(nPoints, nOut)
674 outArray = toEndpoint.arrayFromData(rawOutArray)
675
676 self.assertFalse(transform.hasForward)
677
678 if mapping.hasInverse:
679 self.assertTrue(transform.hasInverse)
680 # inverse transformation of one point;
681 # remember that the inverse need not give the original values
682 # (see the description of the `mapping` parameter)
683 inversePoint = transform.applyInverse(outPoint)
684 rawInversePoint = fromEndpoint.dataFromPoint(inversePoint)
685 assert_allclose(rawInversePoint, mapping.applyInverse(rawOutPoint), err_msg=msg)
686 assert_allclose(rawInversePoint, mappingFromTransform.applyInverse(rawOutPoint), err_msg=msg)
687
688 # inverse transformation of an array of points;
689 # remember that the inverse will not give the original values
690 # (see the description of the `mapping` parameter)
691 inverseArray = transform.applyInverse(outArray)
692 rawInverseArray = fromEndpoint.dataFromArray(inverseArray)
693 self.assertFloatsAlmostEqual(rawInverseArray, mapping.applyInverse(rawOutArray), msg=msg)
694 self.assertFloatsAlmostEqual(rawInverseArray, mappingFromTransform.applyInverse(rawOutArray),
695 msg=msg)
696 else:
697 self.assertFalse(transform.hasInverse)
698

◆ checkTransformFromFrameSet()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkTransformFromFrameSet ( self,
fromName,
toName )
Check Transform_<fromName>_<toName> using the FrameSet constructor

Parameters
----------
fromName, toName : `str`
    Endpoint name prefix for "from" and "to" endpoints, respectively,
    e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`

Definition at line 819 of file testUtils.py.

819 def checkTransformFromFrameSet(self, fromName, toName):
820 """Check Transform_<fromName>_<toName> using the FrameSet constructor
821
822 Parameters
823 ----------
824 fromName, toName : `str`
825 Endpoint name prefix for "from" and "to" endpoints, respectively,
826 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
827 """
828 transformClassName = "Transform{}To{}".format(fromName, toName)
829 TransformClass = getattr(afwGeom, transformClassName)
830 baseMsg = "TransformClass={}".format(TransformClass.__name__)
831 for nIn, nOut in itertools.product(self.goodNAxes[fromName],
832 self.goodNAxes[toName]):
833 msg = "{}, nIn={}, nOut={}".format(baseMsg, nIn, nOut)
834
835 baseFrame = self.makeGoodFrame(fromName, nIn)
836 currFrame = self.makeGoodFrame(toName, nOut)
837 frameSet = self.makeFrameSet(baseFrame, currFrame)
838 self.assertEqual(frameSet.nFrame, 4)
839
840 # construct 0 or more frame sets that are invalid for this transform class
841 for badBaseFrame in self.makeBadFrames(fromName):
842 badFrameSet = self.makeFrameSet(badBaseFrame, currFrame)
843 with self.assertRaises(InvalidParameterError):
844 TransformClass(badFrameSet)
845 for badCurrFrame in self.makeBadFrames(toName):
846 reallyBadFrameSet = self.makeFrameSet(badBaseFrame, badCurrFrame)
847 with self.assertRaises(InvalidParameterError):
848 TransformClass(reallyBadFrameSet)
849 for badCurrFrame in self.makeBadFrames(toName):
850 badFrameSet = self.makeFrameSet(baseFrame, badCurrFrame)
851 with self.assertRaises(InvalidParameterError):
852 TransformClass(badFrameSet)
853
854 transform = TransformClass(frameSet)
855
856 desStr = "{}[{}->{}]".format(transformClassName, nIn, nOut)
857 self.assertEqual("{}".format(transform), desStr)
858 self.assertEqual(repr(transform), "lsst.afw.geom." + desStr)
859
860 self.checkPersistence(transform)
861
862 mappingFromTransform = transform.getMapping()
863 transformCopy = TransformClass(mappingFromTransform)
864 self.assertEqual(type(transform), type(transformCopy))
865 self.assertEqual(transform.getMapping(), mappingFromTransform)
866
867 polyMap = makeTwoWayPolyMap(nIn, nOut)
868
869 self.checkTransformation(transform, mapping=polyMap, msg=msg)
870
871 # If the base and/or current frame of frameSet is a SkyFrame,
872 # try permuting that frame (in place, so the connected mappings are
873 # correctly updated). The Transform constructor should undo the permutation,
874 # (via SpherePointEndpoint.normalizeFrame) in its internal copy of frameSet,
875 # forcing the axes of the SkyFrame into standard (longitude, latitude) order
876 for permutedFS in self.permuteFrameSetIter(frameSet):
877 if permutedFS.isBaseSkyFrame:
878 baseFrame = permutedFS.frameSet.getFrame(ast.FrameSet.BASE)
879 # desired base longitude axis
880 desBaseLonAxis = 2 if permutedFS.isBasePermuted else 1
881 self.assertEqual(baseFrame.lonAxis, desBaseLonAxis)
882 if permutedFS.isCurrSkyFrame:
883 currFrame = permutedFS.frameSet.getFrame(ast.FrameSet.CURRENT)
884 # desired current base longitude axis
885 desCurrLonAxis = 2 if permutedFS.isCurrPermuted else 1
886 self.assertEqual(currFrame.lonAxis, desCurrLonAxis)
887
888 permTransform = TransformClass(permutedFS.frameSet)
889 self.checkTransformation(permTransform, mapping=polyMap, msg=msg)
890

◆ checkTransformFromMapping()

lsst.afw.geom.testUtils.TransformTestBaseClass.checkTransformFromMapping ( self,
fromName,
toName )
Check Transform_<fromName>_<toName> using the Mapping constructor

Parameters
----------
fromName, toName : `str`
    Endpoint name prefix for "from" and "to" endpoints, respectively,
    e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
fromAxes, toAxes : `int`
    number of axes in fromFrame and toFrame, respectively

Definition at line 764 of file testUtils.py.

764 def checkTransformFromMapping(self, fromName, toName):
765 """Check Transform_<fromName>_<toName> using the Mapping constructor
766
767 Parameters
768 ----------
769 fromName, toName : `str`
770 Endpoint name prefix for "from" and "to" endpoints, respectively,
771 e.g. "Point2" for `lsst.afw.geom.Point2Endpoint`
772 fromAxes, toAxes : `int`
773 number of axes in fromFrame and toFrame, respectively
774 """
775 transformClassName = "Transform{}To{}".format(fromName, toName)
776 TransformClass = getattr(afwGeom, transformClassName)
777 baseMsg = "TransformClass={}".format(TransformClass.__name__)
778
779 # check valid numbers of inputs and outputs
780 for nIn, nOut in itertools.product(self.goodNAxes[fromName],
781 self.goodNAxes[toName]):
782 msg = "{}, nIn={}, nOut={}".format(baseMsg, nIn, nOut)
783 polyMap = makeTwoWayPolyMap(nIn, nOut)
784 transform = TransformClass(polyMap)
785
786 # desired output from `str(transform)`
787 desStr = "{}[{}->{}]".format(transformClassName, nIn, nOut)
788 self.assertEqual("{}".format(transform), desStr)
789 self.assertEqual(repr(transform), "lsst.afw.geom." + desStr)
790
791 self.checkTransformation(transform, polyMap, msg=msg)
792
793 # Forward transform but no inverse
794 polyMap = makeForwardPolyMap(nIn, nOut)
795 transform = TransformClass(polyMap)
796 self.checkTransformation(transform, polyMap, msg=msg)
797
798 # Inverse transform but no forward
799 polyMap = makeForwardPolyMap(nOut, nIn).inverted()
800 transform = TransformClass(polyMap)
801 self.checkTransformation(transform, polyMap, msg=msg)
802
803 # check invalid # of output against valid # of inputs
804 for nIn, badNOut in itertools.product(self.goodNAxes[fromName],
805 self.badNAxes[toName]):
806 badPolyMap = makeTwoWayPolyMap(nIn, badNOut)
807 msg = "{}, nIn={}, badNOut={}".format(baseMsg, nIn, badNOut)
808 with self.assertRaises(InvalidParameterError, msg=msg):
809 TransformClass(badPolyMap)
810
811 # check invalid # of inputs against valid and invalid # of outputs
812 for badNIn, nOut in itertools.product(self.badNAxes[fromName],
813 self.goodNAxes[toName] + self.badNAxes[toName]):
814 badPolyMap = makeTwoWayPolyMap(badNIn, nOut)
815 msg = "{}, badNIn={}, nOut={}".format(baseMsg, nIn, nOut)
816 with self.assertRaises(InvalidParameterError, msg=msg):
817 TransformClass(badPolyMap)
818

◆ getTestDir()

lsst.afw.geom.testUtils.TransformTestBaseClass.getTestDir ( self)
Return a directory where temporary test files can be written

The default implementation returns the test directory of the `afw`
package.

If this class is used by a test in a package other than `afw`
then the subclass must override this method.

Definition at line 341 of file testUtils.py.

341 def getTestDir(self):
342 """Return a directory where temporary test files can be written
343
344 The default implementation returns the test directory of the `afw`
345 package.
346
347 If this class is used by a test in a package other than `afw`
348 then the subclass must override this method.
349 """
350 return os.path.join(lsst.utils.getPackageDir("afw"), "tests")
351

◆ makeBadFrames()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeBadFrames ( name)
static
Return a list of 0 or more frames that are not a valid match for the
named endpoint

Parameters
----------
name : `str`
    Endpoint class name prefix; the full class name is name + "Endpoint"

Returns
-------
Collection of `ast.Frame`
    A collection of 0 or more frames

Definition at line 494 of file testUtils.py.

494 def makeBadFrames(name):
495 """Return a list of 0 or more frames that are not a valid match for the
496 named endpoint
497
498 Parameters
499 ----------
500 name : `str`
501 Endpoint class name prefix; the full class name is name + "Endpoint"
502
503 Returns
504 -------
505 Collection of `ast.Frame`
506 A collection of 0 or more frames
507 """
508 return {
509 "Generic": [],
510 "Point2": [
511 ast.SkyFrame(),
512 ast.Frame(1),
513 ast.Frame(3),
514 ],
515 "SpherePoint": [
516 ast.Frame(1),
517 ast.Frame(2),
518 ast.Frame(3),
519 ],
520 }[name]
521
Frame is used to represent a coordinate system.
Definition Frame.h:157
SkyFrame is a specialised form of Frame which describes celestial longitude/latitude coordinate syste...
Definition SkyFrame.h:66

◆ makeEndpoint()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeEndpoint ( name,
nAxes = None )
static
Make an endpoint

Parameters
----------
name : `str`
    Endpoint class name prefix; the full class name is name + "Endpoint"
nAxes : `int` or `None`, optional
    number of axes; an int is required if `name` == "Generic";
    otherwise ignored

Returns
-------
subclass of `lsst.afw.geom.BaseEndpoint`
    The constructed endpoint

Raises
------
TypeError
    If `name` == "Generic" and `nAxes` is None or <= 0

Definition at line 440 of file testUtils.py.

440 def makeEndpoint(name, nAxes=None):
441 """Make an endpoint
442
443 Parameters
444 ----------
445 name : `str`
446 Endpoint class name prefix; the full class name is name + "Endpoint"
447 nAxes : `int` or `None`, optional
448 number of axes; an int is required if `name` == "Generic";
449 otherwise ignored
450
451 Returns
452 -------
453 subclass of `lsst.afw.geom.BaseEndpoint`
454 The constructed endpoint
455
456 Raises
457 ------
458 TypeError
459 If `name` == "Generic" and `nAxes` is None or <= 0
460 """
461 EndpointClassName = name + "Endpoint"
462 EndpointClass = getattr(afwGeom, EndpointClassName)
463 if name == "Generic":
464 if nAxes is None:
465 raise TypeError("nAxes must be an integer for GenericEndpoint")
466 return EndpointClass(nAxes)
467 return EndpointClass()
468

◆ makeFrameSet()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeFrameSet ( self,
baseFrame,
currFrame )
Make a FrameSet

The FrameSet will contain 4 frames and three transforms connecting them.
The idenity of each frame is provided by self.frameIdentDict

Frame       Index   Mapping from this frame to the next
`baseFrame`   1     `ast.UnitMap(nIn)`
Frame(nIn)    2     `polyMap`
Frame(nOut)   3     `ast.UnitMap(nOut)`
`currFrame`   4

where:
- `nIn` = `baseFrame.nAxes`
- `nOut` = `currFrame.nAxes`
- `polyMap` = `makeTwoWayPolyMap(nIn, nOut)`

Returns
------
`ast.FrameSet`
    The FrameSet as described above

Parameters
----------
baseFrame : `ast.Frame`
    base frame
currFrame : `ast.Frame`
    current frame

Definition at line 522 of file testUtils.py.

522 def makeFrameSet(self, baseFrame, currFrame):
523 """Make a FrameSet
524
525 The FrameSet will contain 4 frames and three transforms connecting them.
526 The idenity of each frame is provided by self.frameIdentDict
527
528 Frame Index Mapping from this frame to the next
529 `baseFrame` 1 `ast.UnitMap(nIn)`
530 Frame(nIn) 2 `polyMap`
531 Frame(nOut) 3 `ast.UnitMap(nOut)`
532 `currFrame` 4
533
534 where:
535 - `nIn` = `baseFrame.nAxes`
536 - `nOut` = `currFrame.nAxes`
537 - `polyMap` = `makeTwoWayPolyMap(nIn, nOut)`
538
539 Returns
540 ------
541 `ast.FrameSet`
542 The FrameSet as described above
543
544 Parameters
545 ----------
546 baseFrame : `ast.Frame`
547 base frame
548 currFrame : `ast.Frame`
549 current frame
550 """
551 nIn = baseFrame.nAxes
552 nOut = currFrame.nAxes
553 polyMap = makeTwoWayPolyMap(nIn, nOut)
554
555 # The only way to set the Ident of a frame in a FrameSet is to set it in advance,
556 # and I don't want to modify the inputs, so replace the input frames with copies
557 baseFrame = baseFrame.copy()
558 baseFrame.ident = self.frameIdentDict[1]
559 currFrame = currFrame.copy()
560 currFrame.ident = self.frameIdentDict[4]
561
562 frameSet = ast.FrameSet(baseFrame)
563 frame2 = ast.Frame(nIn)
564 frame2.ident = self.frameIdentDict[2]
565 frameSet.addFrame(ast.FrameSet.CURRENT, ast.UnitMap(nIn), frame2)
566 frame3 = ast.Frame(nOut)
567 frame3.ident = self.frameIdentDict[3]
568 frameSet.addFrame(ast.FrameSet.CURRENT, polyMap, frame3)
569 frameSet.addFrame(ast.FrameSet.CURRENT, ast.UnitMap(nOut), currFrame)
570 return frameSet
571
A FrameSet consists of a set of one or more Frames (which describe coordinate systems),...
Definition FrameSet.h:99
A UnitMap is a unit (null) Mapping that has no effect on the coordinates supplied to it.
Definition UnitMap.h:44

◆ makeGoodFrame()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeGoodFrame ( cls,
name,
nAxes = None )
Return the appropriate frame for the given name and nAxes

Parameters
----------
name : `str`
    Endpoint class name prefix; the full class name is name + "Endpoint"
nAxes : `int` or `None`, optional
    number of axes; an int is required if `name` == "Generic";
    otherwise ignored

Returns
-------
`ast.Frame`
    The constructed frame

Raises
------
TypeError
    If `name` == "Generic" and `nAxes` is `None` or <= 0

Definition at line 470 of file testUtils.py.

470 def makeGoodFrame(cls, name, nAxes=None):
471 """Return the appropriate frame for the given name and nAxes
472
473 Parameters
474 ----------
475 name : `str`
476 Endpoint class name prefix; the full class name is name + "Endpoint"
477 nAxes : `int` or `None`, optional
478 number of axes; an int is required if `name` == "Generic";
479 otherwise ignored
480
481 Returns
482 -------
483 `ast.Frame`
484 The constructed frame
485
486 Raises
487 ------
488 TypeError
489 If `name` == "Generic" and `nAxes` is `None` or <= 0
490 """
491 return cls.makeEndpoint(name, nAxes).makeFrame()
492

◆ makeJacobian()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeJacobian ( nIn,
nOut,
inPoint )
static
Make a Jacobian matrix for the equation described by
`makeTwoWayPolyMap`.

Parameters
----------
nIn, nOut : `int`
    the dimensions of the input and output data; see makeTwoWayPolyMap
inPoint : `numpy.ndarray`
    an array of size `nIn` representing the point at which the Jacobian
    is measured

Returns
-------
J : `numpy.ndarray`
    an `nOut` x `nIn` array of first derivatives

Definition at line 595 of file testUtils.py.

595 def makeJacobian(nIn, nOut, inPoint):
596 """Make a Jacobian matrix for the equation described by
597 `makeTwoWayPolyMap`.
598
599 Parameters
600 ----------
601 nIn, nOut : `int`
602 the dimensions of the input and output data; see makeTwoWayPolyMap
603 inPoint : `numpy.ndarray`
604 an array of size `nIn` representing the point at which the Jacobian
605 is measured
606
607 Returns
608 -------
609 J : `numpy.ndarray`
610 an `nOut` x `nIn` array of first derivatives
611 """
612 basePolyMapCoeff = 0.001 # see makeTwoWayPolyMap
613 baseCoeff = 2.0 * basePolyMapCoeff
614 coeffs = np.empty((nOut, nIn))
615 for iOut in range(nOut):
616 coeffOffset = baseCoeff * iOut
617 for iIn in range(nIn):
618 coeffs[iOut, iIn] = baseCoeff * (iIn + 1) + coeffOffset
619 coeffs[iOut, iIn] *= inPoint[iIn]
620 assert coeffs.ndim == 2
621 # Avoid spurious errors when comparing to a simplified array
622 assert coeffs.shape == (nOut, nIn)
623 return coeffs
624

◆ makeRawArrayData()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeRawArrayData ( nPoints,
nAxes,
delta = 0.123 )
static
Make an array of generic point data

The data will be suitable for spherical points

Parameters
----------
nPoints : `int`
    Number of points in the array
nAxes : `int`
    Number of axes in the point

Returns
-------
np.array of floats with shape (nAxes, nPoints)
    The values are as follows; if nAxes != 2:
        The first point has values `[0, delta, 2*delta, ..., (nAxes-1)*delta]`
        The Nth point has those values + N
    if nAxes == 2 then the data is scaled so that the max value of axis 1
        is a bit less than pi/2

Definition at line 389 of file testUtils.py.

389 def makeRawArrayData(nPoints, nAxes, delta=0.123):
390 """Make an array of generic point data
391
392 The data will be suitable for spherical points
393
394 Parameters
395 ----------
396 nPoints : `int`
397 Number of points in the array
398 nAxes : `int`
399 Number of axes in the point
400
401 Returns
402 -------
403 np.array of floats with shape (nAxes, nPoints)
404 The values are as follows; if nAxes != 2:
405 The first point has values `[0, delta, 2*delta, ..., (nAxes-1)*delta]`
406 The Nth point has those values + N
407 if nAxes == 2 then the data is scaled so that the max value of axis 1
408 is a bit less than pi/2
409 """
410 delta = 0.123
411 # oneAxis = [0, 1, 2, ...nPoints-1]
412 oneAxis = np.arange(nPoints, dtype=float) # [0, 1, 2...]
413 # rawData = [oneAxis, oneAxis + delta, oneAxis + 2 delta, ...]
414 rawData = np.array([j * delta + oneAxis for j in range(nAxes)], dtype=float)
415 if nAxes == 2:
416 # scale rawData so that max value of 2nd axis is a bit less than pi/2,
417 # thus making the data safe for SpherePoint
418 maxLatitude = np.max(rawData[1])
419 rawData *= math.pi * 0.4999 / maxLatitude
420 return rawData
421

◆ makeRawPointData()

lsst.afw.geom.testUtils.TransformTestBaseClass.makeRawPointData ( nAxes,
delta = 0.123 )
static
Make one generic point

Parameters
----------
nAxes : `int`
    Number of axes in the point
delta : `float`
    Increment between axis values

Returns
-------
A list of `nAxes` floats with values `[0, delta, ..., (nAxes-1)*delta]

Definition at line 423 of file testUtils.py.

423 def makeRawPointData(nAxes, delta=0.123):
424 """Make one generic point
425
426 Parameters
427 ----------
428 nAxes : `int`
429 Number of axes in the point
430 delta : `float`
431 Increment between axis values
432
433 Returns
434 -------
435 A list of `nAxes` floats with values `[0, delta, ..., (nAxes-1)*delta]
436 """
437 return [i*delta for i in range(nAxes)]
438

◆ permuteFrameSetIter()

lsst.afw.geom.testUtils.TransformTestBaseClass.permuteFrameSetIter ( frameSet)
static
Iterator over 0 or more frameSets with SkyFrames axes permuted

Only base and current SkyFrames are permuted. If neither the base nor
the current frame is a SkyFrame then no frames are returned.

Returns
-------
iterator over `PermutedFrameSet`

Definition at line 573 of file testUtils.py.

573 def permuteFrameSetIter(frameSet):
574 """Iterator over 0 or more frameSets with SkyFrames axes permuted
575
576 Only base and current SkyFrames are permuted. If neither the base nor
577 the current frame is a SkyFrame then no frames are returned.
578
579 Returns
580 -------
581 iterator over `PermutedFrameSet`
582 """
583
584 fsInfo = FrameSetInfo(frameSet)
585 if not (fsInfo.isBaseSkyFrame or fsInfo.isCurrSkyFrame):
586 return
587
588 permuteBaseList = [False, True] if fsInfo.isBaseSkyFrame else [False]
589 permuteCurrList = [False, True] if fsInfo.isCurrSkyFrame else [False]
590 for permuteBase in permuteBaseList:
591 for permuteCurr in permuteCurrList:
592 yield PermutedFrameSet(frameSet, permuteBase, permuteCurr)
593

◆ setUp()

lsst.afw.geom.testUtils.TransformTestBaseClass.setUp ( self)
Set up a test

Subclasses should call this method if they override setUp.

Definition at line 352 of file testUtils.py.

352 def setUp(self):
353 """Set up a test
354
355 Subclasses should call this method if they override setUp.
356 """
357 # tell unittest to use the msg argument of asserts as a supplement
358 # to the error message, rather than as the whole error message
359 self.longMessage = True
360
361 # list of endpoint class name prefixes; the full name is prefix + "Endpoint"
362 self.endpointPrefixes = ("Generic", "Point2", "SpherePoint")
363
364 # GoodNAxes is dict of endpoint class name prefix:
365 # tuple containing 0 or more valid numbers of axes
366 self.goodNAxes = {
367 "Generic": (1, 2, 3, 4), # all numbers of axes are valid for GenericEndpoint
368 "Point2": (2,),
369 "SpherePoint": (2,),
370 }
371
372 # BadAxes is dict of endpoint class name prefix:
373 # tuple containing 0 or more invalid numbers of axes
374 self.badNAxes = {
375 "Generic": (), # all numbers of axes are valid for GenericEndpoint
376 "Point2": (1, 3, 4),
377 "SpherePoint": (1, 3, 4),
378 }
379
380 # Dict of frame index: identity name for frames created by makeFrameSet
381 self.frameIdentDict = {
382 1: "baseFrame",
383 2: "frame2",
384 3: "frame3",
385 4: "currFrame",
386 }
387

Member Data Documentation

◆ badNAxes

lsst.afw.geom.testUtils.TransformTestBaseClass.badNAxes

Definition at line 374 of file testUtils.py.

◆ endpointPrefixes

lsst.afw.geom.testUtils.TransformTestBaseClass.endpointPrefixes

Definition at line 362 of file testUtils.py.

◆ frameIdentDict

lsst.afw.geom.testUtils.TransformTestBaseClass.frameIdentDict

Definition at line 381 of file testUtils.py.

◆ goodNAxes

lsst.afw.geom.testUtils.TransformTestBaseClass.goodNAxes

Definition at line 366 of file testUtils.py.

◆ longMessage

lsst.afw.geom.testUtils.TransformTestBaseClass.longMessage

Definition at line 359 of file testUtils.py.


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