|
53 | 53 | MomentsG1Sky, MomentsG2Sky, MomentsTraceSky, |
54 | 54 | CorrelationIuuSky, CorrelationIvvSky, CorrelationIuvSky, |
55 | 55 | SemimajorAxisFromCorrelation, SemiminorAxisFromCorrelation, |
56 | | - PositionAngleFromCorrelation |
57 | | - PositionAngleFromMoments, ConvertDetectorAngleErrToPositionAngleErr) |
| 56 | + PositionAngleFromCorrelation, |
| 57 | + PositionAngleFromMoments, |
| 58 | + ConvertDetectorAngleErrToPositionAngleErr) |
58 | 59 |
|
59 | 60 | ROOT = os.path.abspath(os.path.dirname(__file__)) |
60 | 61 |
|
@@ -763,70 +764,6 @@ def testConvertDetectorAngleToPositionAngle(self): |
763 | 764 |
|
764 | 765 | np.testing.assert_allclose(coord_diff, 0, rtol=0, atol=5e-6) |
765 | 766 |
|
766 | | - # Test position angle error propogation |
767 | | - def testConvertDetectorAngleErrToPositionAngleErr(self): |
768 | | - """Test conversion of position angle err in detector degrees to |
769 | | - position angle erron sky |
770 | | - """ |
771 | | - dipoleSep = 10 |
772 | | - ixx = 10 |
773 | | - testPixelDeltas = np.random.uniform(-100, 100, size=(self.nRecords, 2)) |
774 | | - # testConvertPixelToArcSecond uses a meas_base LocalWcsPlugin |
775 | | - # but we're using a simple WCS as our example, so this doesn't really matter |
776 | | - # and we'll just use the WCS directly |
777 | | - for dec in np.linspace(-90, 90, 10): |
778 | | - for theta in (-45, 0, 90): |
779 | | - for x, y in zip(np.random.uniform(2 * 1109.99981456774, size=10), |
780 | | - np.random.uniform(2 * 560.018167811613, size=10)): |
781 | | - wcs = self._makeWcs(dec=dec, theta=theta) |
782 | | - cd_matrix = wcs.getCdMatrix() |
783 | | - |
784 | | - self.dataDict["dipoleSep"] = np.full(self.nRecords, dipoleSep) |
785 | | - self.dataDict["ixx"] = np.full(self.nRecords, ixx) |
786 | | - self.dataDict["slot_Centroid_x"] = np.full(self.nRecords, x) |
787 | | - self.dataDict["slot_Centroid_y"] = np.full(self.nRecords, y) |
788 | | - self.dataDict["someCentroid_x"] = x + testPixelDeltas[:, 0] |
789 | | - self.dataDict["someCentroid_y"] = y + testPixelDeltas[:, 1] |
790 | | - self.dataDict["orientation"] = np.arctan2( |
791 | | - self.dataDict["someCentroid_y"] - self.dataDict["slot_Centroid_y"], |
792 | | - self.dataDict["someCentroid_x"] - self.dataDict["slot_Centroid_x"], |
793 | | - ) |
794 | | - self.dataDict["orientation_err"] = np.arctan2( |
795 | | - self.dataDict["someCentroid_y"] - self.dataDict[ "slot_Centroid_y"], |
796 | | - self.dataDict["someCentroid_x"] - self.dataDict["slot_Centroid_x"], |
797 | | - )*.001 |
798 | | - |
799 | | - self.dataDict["base_LocalWcs_CDMatrix_1_1"] = np.full(self.nRecords, |
800 | | - cd_matrix[0, 0]) |
801 | | - self.dataDict["base_LocalWcs_CDMatrix_1_2"] = np.full(self.nRecords, |
802 | | - cd_matrix[0, 1]) |
803 | | - self.dataDict["base_LocalWcs_CDMatrix_2_1"] = np.full(self.nRecords, |
804 | | - cd_matrix[1, 0]) |
805 | | - self.dataDict["base_LocalWcs_CDMatrix_2_2"] = np.full(self.nRecords, |
806 | | - cd_matrix[1, 1]) |
807 | | - df = self.getMultiIndexDataFrame(self.dataDict) |
808 | | - |
809 | | - # Test detector angle to position angle conversion |
810 | | - func = ConvertDetectorAngleErrToPositionAngleErr( |
811 | | - "orientation", |
812 | | - "orientation_err", |
813 | | - "base_LocalWcs_CDMatrix_1_1", |
814 | | - "base_LocalWcs_CDMatrix_1_2", |
815 | | - "base_LocalWcs_CDMatrix_2_1", |
816 | | - "base_LocalWcs_CDMatrix_2_2" |
817 | | - ) |
818 | | - |
819 | | - func_pa = ConvertDetectorAngleToPositionAngle( |
820 | | - "orientation", |
821 | | - "base_LocalWcs_CDMatrix_1_1", |
822 | | - "base_LocalWcs_CDMatrix_1_2", |
823 | | - "base_LocalWcs_CDMatrix_2_1", |
824 | | - "base_LocalWcs_CDMatrix_2_2" |
825 | | - ) |
826 | | - val = self._funcVal(func, df) |
827 | | - val_pa = self._funcVal(func_pa, df) |
828 | | - |
829 | | - |
830 | 767 | def testConvertPixelToArcseconds(self): |
831 | 768 | """Test calculations of the pixel scale, conversions of pixel to |
832 | 769 | arcseconds. |
@@ -924,6 +861,111 @@ def testConvertPixelToArcseconds(self): |
924 | 861 | atol=1e-16, |
925 | 862 | rtol=1e-16)) |
926 | 863 |
|
| 864 | + def testConvertDetectorAngleErrToPositionAngleErr(self): |
| 865 | + """Test conversion of position angle err in detector degrees to |
| 866 | + position angle err on sky. |
| 867 | +
|
| 868 | + Requires a similar setup to testConvertDetectorAngleToPositionAngle. |
| 869 | + """ |
| 870 | + import pydevd_pycharm |
| 871 | + pydevd_pycharm.settrace('localhost', port=8888, stdout_to_server=True, |
| 872 | + stderr_to_server=True) |
| 873 | + dipoleSep = 10 |
| 874 | + ixx = 10 |
| 875 | + testPixelDeltas = np.random.uniform(-100, 100, size=(self.nRecords, 2)) |
| 876 | + |
| 877 | + for dec in np.linspace(-80, 80, 10): |
| 878 | + for theta in (-35, 0, 90): |
| 879 | + for x, y in zip( |
| 880 | + np.random.uniform(2 * 1109.99981456774, size=10), |
| 881 | + np.random.uniform(2 * 560.018167811613, size=10)): |
| 882 | + wcs = self._makeWcs(dec=dec, theta=theta) |
| 883 | + cd_matrix = wcs.getCdMatrix() |
| 884 | + |
| 885 | + self.dataDict["dipoleSep"] = np.full(self.nRecords, |
| 886 | + dipoleSep) |
| 887 | + self.dataDict["ixx"] = np.full(self.nRecords, ixx) |
| 888 | + self.dataDict["slot_Centroid_x"] = np.full(self.nRecords, |
| 889 | + x) |
| 890 | + self.dataDict["slot_Centroid_y"] = np.full(self.nRecords, |
| 891 | + y) |
| 892 | + self.dataDict["someCentroid_x"] = x + testPixelDeltas[:, 0] |
| 893 | + self.dataDict["someCentroid_y"] = y + testPixelDeltas[:, 1] |
| 894 | + self.dataDict["orientation"] = np.arctan2( |
| 895 | + self.dataDict["someCentroid_y"] - self.dataDict[ |
| 896 | + "slot_Centroid_y"], |
| 897 | + self.dataDict["someCentroid_x"] - self.dataDict[ |
| 898 | + "slot_Centroid_x"], |
| 899 | + ) |
| 900 | + self.dataDict["orientation_err"] = np.arctan2( |
| 901 | + self.dataDict["someCentroid_y"] - self.dataDict[ |
| 902 | + "slot_Centroid_y"], |
| 903 | + self.dataDict["someCentroid_x"] - self.dataDict[ |
| 904 | + "slot_Centroid_x"], |
| 905 | + ) * .001 |
| 906 | + |
| 907 | + self.dataDict["base_LocalWcs_CDMatrix_1_1"] = np.full( |
| 908 | + self.nRecords, |
| 909 | + cd_matrix[0, 0]) |
| 910 | + self.dataDict["base_LocalWcs_CDMatrix_1_2"] = np.full( |
| 911 | + self.nRecords, |
| 912 | + cd_matrix[0, 1]) |
| 913 | + self.dataDict["base_LocalWcs_CDMatrix_2_1"] = np.full( |
| 914 | + self.nRecords, |
| 915 | + cd_matrix[1, 0]) |
| 916 | + self.dataDict["base_LocalWcs_CDMatrix_2_2"] = np.full( |
| 917 | + self.nRecords, |
| 918 | + cd_matrix[1, 1]) |
| 919 | + df = self.getMultiIndexDataFrame(self.dataDict) |
| 920 | + |
| 921 | + # Test detector angle err to position angle err conversion |
| 922 | + func = ConvertDetectorAngleErrToPositionAngleErr( |
| 923 | + "orientation", |
| 924 | + "orientation_err", |
| 925 | + "base_LocalWcs_CDMatrix_1_1", |
| 926 | + "base_LocalWcs_CDMatrix_1_2", |
| 927 | + "base_LocalWcs_CDMatrix_2_1", |
| 928 | + "base_LocalWcs_CDMatrix_2_2" |
| 929 | + ) |
| 930 | + val = self._funcVal(func, df) |
| 931 | + |
| 932 | + # Numerical derivative of the same PA function so a |
| 933 | + # compariosn can be made |
| 934 | + step = 1.0e-7 # radians. Bigger? Smaller? |
| 935 | + pa_plus_deg = func.getPositionAngleFromDetectorAngle( |
| 936 | + df[("meas", "g", "orientation")] + step, |
| 937 | + df[("meas", "g", "base_LocalWcs_CDMatrix_1_1")], |
| 938 | + df[("meas", "g", "base_LocalWcs_CDMatrix_1_2")], |
| 939 | + df[("meas", "g", "base_LocalWcs_CDMatrix_2_1")], |
| 940 | + df[("meas", "g", "base_LocalWcs_CDMatrix_2_2")], |
| 941 | + ) |
| 942 | + pa_minus_deg = func.getPositionAngleFromDetectorAngle( |
| 943 | + df[("meas", "g", "orientation")] - step, |
| 944 | + df[("meas", "g", "base_LocalWcs_CDMatrix_1_1")], |
| 945 | + df[("meas", "g", "base_LocalWcs_CDMatrix_1_2")], |
| 946 | + df[("meas", "g", "base_LocalWcs_CDMatrix_2_1")], |
| 947 | + df[("meas", "g", "base_LocalWcs_CDMatrix_2_2")], |
| 948 | + ) |
| 949 | + |
| 950 | + pa_plus = np.deg2rad(pa_plus_deg.to_numpy()) |
| 951 | + pa_minus = np.deg2rad(pa_minus_deg.to_numpy()) |
| 952 | + |
| 953 | + # From example: smallest signed angular difference in |
| 954 | + # (-pi, +pi] |
| 955 | + dpa = np.angle(np.exp(1j * (pa_plus - pa_minus))) |
| 956 | + dpa_dtheta = dpa / (2.0 * step) |
| 957 | + |
| 958 | + theta_err = df[("meas", "g", "orientation_err")].to_numpy() |
| 959 | + expected_pa_err_deg = np.rad2deg( |
| 960 | + np.abs(dpa_dtheta) * theta_err) |
| 961 | + |
| 962 | + np.testing.assert_allclose( |
| 963 | + val.to_numpy(), |
| 964 | + expected_pa_err_deg, |
| 965 | + rtol=0, |
| 966 | + atol=5e-6, |
| 967 | + ) |
| 968 | + |
927 | 969 | def _makeWcs(self, dec=53.1595451514076, theta=0): |
928 | 970 | """Create a wcs from real CFHT values, rotated by an optional theta. |
929 | 971 |
|
|
0 commit comments